ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • OpenAPI와 스웨거를 활용한 실전 API 설계를 읽고 ... (3)
    개발하면서/타인글보면서 2024. 5. 10. 20:00
    반응형

    2부는 백지상태에서 서비스 오픈까지의 과정을 알아봤다면
    3부에선 펫시터 오픈 이후 API 확장과 진화되는 과정을 알아본다.

    OpenAPI의 고급 주제를 다룬다.

     

    스프린트라는 단어는 소프트웨어 개발 프로젝트에서 시간 블록을 의미한다.

    1. 요구사항을 모두 확인하여 달성율을 판단하고 (회고, 피드백),

    2. 다음에는 어떤 걸 할 수 있고 무엇을 해야 하는지 확인하는 과정이다. (계획, 준비)

    한 스프린트에서 우선순위 목록을 나열하고 도메인 모델 재검토, 사용자 스토리 검토하는 내용이 나온다.

     

    개인적으로 스프린트에서 가장 중요하다고 생각하는건
    하나의 스프린트에 끝낼 수 있는 크기의 것으로 시작하는 것이다. (두 번째는 임팩트라고 생각)

    요구사항이 크고 복잡하다면 한 스프린트에 달성 가능한 크기로 잘게 쪼개도록 의도적으로 노력한다.

    철저한 준비도 물론 중요하지만 빠른 행동과 피드백 개선의 사이클을 돌리는 게 더 유리하기 때문이다. (내가 하는 일 기준)

     

    도메인 모델과 다형성

    지난 시간에는 반려견만 정의했었는데, 반려묘도 추가해 달라는 요구사항이 생겼다.

    Pet이라는 슈퍼타입과 Dog, Cat 서브타입으로 도메인 모델을 구성했는데 이를 OpenAPI에 정의해 본다.

     

    아직 상속관계를 반영하지 않은 OpenAPI 정의서다.

    openapi: 3.0.3
    #...
    components:
      schemas:
        Pet:
          type: object
          properties:
            name:
              type: string
            age:
              type: integer
        Dog:
          type: object
          properties:
            breed:
              type: string
            size:
              type: string
        Cat:
          type: object
          properties:
            breed:
              type: string

     

    OpenAPI에는 상속과 관련하여 allOf, anyOf, oneOf, not, 이렇게 4가지 키워드가 있으며 이를 Composition keyword라고 한다.

    allOf는 교집합, anyOf는 합집합, oneOf는 XOR, not은 not으로 요약할 수 있다.

     

    openapi: 3.0.3
    #...
    components:
      schemas:
        Pet:
          allOf:
          - type: object
            properties:
              name:
                type: string
              age:
                type: integer
          - oneOf:
            - $ref: '#/components/schemas/Dog'
            - $ref: '#/components/schemas/Cat'
        Dog:
          type: object
          properties:
            breed:
              type: string
            size:
              type: string
        Cat:
          type: object
          properties:
            breed:
              type: string

     

    지금까지 정의된 Pet JSON 객체를 보고 Dog인지 Cat인지 구분하기는 쉽지 않은데

    이때 스키마 구분하는 용도인 discriminator를 사용하자.

    oneOf와 같은 레벨에 discriminator를 사용하면 Dog인지 Cat인지 스키마 구분이 쉬워진다.

    openapi: 3.0.3
    #...
    components:
      schemas:
        Pet:
          allOf:
          - type: object
            properties:
              name:
                type: string
              age:
                type: integer
          - oneOf:
            - $ref: '#/components/schemas/Dog'
            - $ref: '#/components/schemas/Cat'
          discriminator:
            propertyName: species   # <-- 구분자로 사용할 프로퍼티 명
            mapping:
              Dog: '#/components/schemas/Dog'
              Cat: '#/components/schemas/Cat'
        Dog:
          type: object
          properties:
            breed:
              type: string
            size:
              type: string
            species:
              type: string
          required:
            - species
        Cat:
          type: object
          properties:
            breed:
              type: string
            species:
              type: string
          required:
            - species

     

     

    필터와 정렬

    필터, 정렬 구현할 때 참고하면 좋은 Stripe API 문서

     

    Stripe API Reference

    stripe trigger ▶️ [event]

    docs.stripe.com

     

    필드를 선택해서 조회하는 프로젝션 필터는 구현이 복잡해서 패스!!

    셀렉션 필터(정렬, 페이징, 우리가 아는 필터)를 구현할 때 일관성 있게 구성하는 방법을 소개한다.

    openapi: 3.0.3
    paths:
      #...
      /jobs:
        post:
          #...
        get:
          summary: List/Search Available Jobs
          operationId: listOrSearchAvailableJobs
          parameters:
            - name: start_time_before
              in: query
              description: Search jobs starting before this date and time.
              schema:
                type: string
                format: date-time
            - name: start_time_after
              in: query
              description: Search jobs starting bafter this date and time.
              schema:
                type: string
                format: date-time
            #...
            - name: activity
              description: |
                Performs a full-text search for the phrase entered in job activies
              schema:
                type: string
            - name: pets
              in: query
              description: Searches for pets matching specific criteria.
              style: deepObject # <-- 객체이름[속성이름] 스타일로 직렬화 된다.
              schema:
                type: object
                properties:
                  age_below:
                    type: integer
                    description: Return only pets with this age or younger.
                  #...
                  species:
                    type: string
                    description: |
                      Return only pets with this species.
                      Provide multiple species as comma-seperated values.

     

     

    페이징

    한 페이지에 보여줄 개수와 현재 offset으로 페이징을 구현하는 오프셋 기반 페이징 방법

    한 페이지에 보여줄 개수와 페이지를 식별할 수 있는 cursor로 페이징을 구현하는 커서 기반 페이징 방법이 있다.

    책에선 커서 기반 페이징 방법으로 OpenAPI를 작성한다.

    openapi: 3.0.3
    #...
    paths:
      /jobs:
        get:
          #...
          parameters:
            #...  필터
            - name: limit
              in: query
              description: The maximum number of results to return.
              schema:
                type: integer
                default: 20
                maximum: 100
            - name: cursor
              in: query
              description: |
                Use the cursor from the response to access more results.
              schema:
                type: string
        responses:
          '200':
            #...
            properties:
              items:
                type: array
                items:
                  $ref: '#/components/schemas/Job'
              cursor:
                type: string
                description: Cursor for the next result page.
                nullable:true

     

     

    정렬

    파라미터 설계에서 가장 중요한 것은 일관성이다.

    아래 8개 예시에서 일관된 스타일은 1, 2, 3이다. 4~8는 일관되지 않고 제멋대로다.

     

    1. created_before=2020-07-01&sort=author&order_by=desc

    2. created=lt:2020-07-01&sort=author:desc

    3. created=<2020-07-01&sort=-desc

    4. created=<2020-07-01&sort_by=author&order_by=desc

    5. created.lt=2020-07-01&sort_by=-author

    6. created=lt:2020-07-01&sort_by=-author

    7. created=<2020-07-01&sort_by=author:desc

    8. created=lt:2020-07-01&sort_by=author.desc

    openapi: 3.0.3
    #...
    paths:
      /jobs:
        get:
          #...
          parameters:
            #...  필터와 정렬
            - name: sort
              in: query
              description: |
                Indicate the sorting key and direction for the results.
                Use the field name, suffixed with ":asc" for ascending
                or ":desc" for descending order.
                Valid fields: start_time, end_time, activity
              schema:
                type: string

     

     

    각 주제에서 기능 부분만 간추렸는데 OpenAPI 스펙을 작성하기까지의 고민하는 과정과

    일관성을 유지하기 위해 어떤 점들을 고려했는지 친절하게 얘기하듯이 책은 얘기하고 있다.

    관심이 있다면 꼭! 책을 읽어보자.

    반응형

    댓글

Designed by Tistory.