Programing

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

lottogame 2020. 10. 13. 07:17
반응형

상속을 사용하여 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 체계의 변경없이 추가 전문화 (예 : 더 많은 동물 유형)를 추가 할 수있는 기능을 제공합니다.


나는 개와 물고기의 목록을 반환하는 / 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="/animals/123">
    <name>Fido</name>
    <fur-color>White</fur-color>
  </animal>
  <animal type="fish" href="/animals/321">
    <name>Wanda</name>
    <water-type>Salt</water-type>
  </animal>
</animals>

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


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

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

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

However, in the OpenAPI (former Swagger), schemas composition has been enhanced by the keywords discriminator (v2.0+) and oneOf (v3.0+) to truly support polymorphism.

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

Your inheritance could be modeled using a combination of oneOf (for choosing one of the subtypes) and allOf (for combining the type and one of its subtypes). Below is a sample definition for the POST method.

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

But now the relationship between dogs and cats is lost.

Indeed, but keep in mind that URI simply never reflects relations between objects.


I know this is an old question, but I'm interested in investigating further issues on a RESTful inheritance modeling

I can always say that a dog is an animal and hen too, but hen makes eggs while dog is a mammal, so it can't. An API like

GET animals/:animalID/eggs

is not consistent because indicates that all subtypes of animal can have eggs (as a consequence of Liskov substitution). There would be a fallback if all mammals respond with '0' to this request, but what if I also enable a POST method? Should I be afraid that tomorrow there would be dog eggs in my crepes?

The only way to handle these scenarios is to provide a 'super-resource' which aggregates all the subresources shared among all possibile 'derived-resource' and then a specialization for each derived-resource that needs it, just like when we downcast an object into oop

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

The drawback, here, is that someone could pass a dog Id to reference an instance of hens collection, but the dog is not an hen, so it would not be incorrect if the response was 404 or 400 with a reason message

Am I wrong?

참고URL : https://stackoverflow.com/questions/10880472/how-to-model-a-restful-api-with-inheritance

반응형