소개#
프론트엔드와 백엔드 팀이 순차적으로 작업하는 것——백엔드가 API를 구축한 다음 프론트엔드가 통합하는 것——은 느립니다. 이 글에서는 OpenAPI로 API 계약을 먼저 정의하여 두 팀이 병렬로 작업할 수 있도록 변경한 방법을 설명합니다.
배경 및 동기#
Retrospec 피드백은 API의 가시성과 계획에서 중요한 격차를 강조했습니다. 급속한 기술 발전으로 인해 동적이고 적응 가능한 시스템에 대한 필요성이 증가하고 있습니다. 제안된 방법은 계획 단계에서 백엔드와 프론트엔드 엔지니어를 모두 포함하여 처음부터 명확성과 일치를 보장하는 것을 목표로 합니다.
제안된 프로세스#
1. 대표자 선택:#
매주 한 명의 백엔드와 한 명의 프론트엔드 엔지니어가 선택됩니다. 이 대표자들은 스프린트의 요구 사항을 이해하고 현재 계획 OpenAPI 스키마와 일치시키는 책임을 집니다.
2. 검토 및 수정:#
선택된 엔지니어는 협력하여 OpenAPI 구성을 검토합니다. 그들은 요구 사항과 일치하는지 확인하고 필요한 경우 수정합니다. 이 협업은 양측이 달성해야 할 사항을 명확하게 이해할 수 있도록 보장합니다.
3. 커밋 및 생성:#
수정 후 OpenAPI 구성에 대한 변경 사항이 해당 리포지토리에 커밋됩니다. 이에 이어 CI/CD는 제공된 yaml을 사용하여 목 API를 생성합니다.
4. 스프린트 완료:#
스프린트 완료 시 새 yaml이 생성됩니다. 이 yaml은 다음 스프린트의 API 요구 사항을 캡슐화합니다.
도구 및 관리:#
YAML 시각화: Swagger Editor에 있는 온라인 도구를 활용하여 yaml을 업로드하고 Swagger 문서로 시각화할 수 있습니다.
OpenAPI 문서 관리: 이 제안된 프로세스는 순전히 계획 단계를 위한 것임을 이해하는 것이 중요합니다. API가 배포되면 해당 서비스는 자체 openapi.json을 생성해야 합니다. 이 JSON은 다운로드하여 추가 계획에 재사용할 수 있습니다.
CI/CD 역할: CI/CD 파이프라인은 중추적인 역할을 합니다. yaml 파일을 수락하고 사양에 따라 목 서버를 배포하도록 설계되어야 합니다. 이 목적을 위해 openapi-mock와 같은 도구를 고려할 수 있습니다.
이 프로세스가 유익한 이유:#
향상된 커뮤니케이션: 계획 프로세스에 백엔드와 프론트엔드 엔지니어를 모두 포함함으로써 직접적인 커뮤니케이션 라인이 확립됩니다. 이것은 오해와 모호함을 최소화하여 더 간소화된 개발 프로세스를 만듭니다.
개선된 정렬: 두 팀 모두 API 요구 사항과 기능에 대한 명확한 이해와 합의를 가질 수 있습니다. 이것은 개발 단계 동안 왕복이 줄어든다는 것을 의미합니다.
효율성: 사양에 따라 목 서버가 배포되면 개발자는 지연 없이 작업을 시작할 수 있어 더 빠른 제품 릴리스로 이어집니다.
품질 보증: 백엔드와 프론트엔드 개발자가 처음부터 참여하면 중요한 요구 사항을 간과할 가능성이 줄어듭니다. 이것은 더 견고하고 잘 작동하는 최종 제품을 만듭니다.
결론#
먼저 OpenAPI로 API 계약을 정의하고, 목 서버를 생성한 다음, 두 팀이 병렬로 작업하게 하세요. 사전 계획에 투자하는 시간은 통합 시 예상치 못한 문제가 줄어들고 더 빠른 제공으로 충분히 보상받습니다.
부록 A - yaml 예제#
openapi: 3.1.0
info:
title: PKY Sprint 3
description: |-
PKY Sprint 3 Development Schema
termsOfService:
contact:
email: jared@lynskey.co.nz
license:
name: None
url:
version: 1.0.11
externalDocs:
description:
url:
servers:
- url: https://api-mock.com/api/v3
tags:
- name: curation
description: PKY-1081 Curated Lists Feature
externalDocs:
description: Jira Epic
url: https://pickydev.atlassian.net/browse/PKY-1081
paths:
/curations:
get:
tags:
- curation
summary: Return the curations created by users
description: Returns a map of status codes to quantities
operationId: getCurations
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: object
additionalProperties:
type: integer
format: int32
security:
- api_key: []
/curations/{curationId}:
get:
tags:
- curation
summary: Find purchase order by ID
description: For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.
operationId: getOrderById
parameters:
- name: orderId
in: path
description: ID of order that needs to be fetched
required: true
schema:
type: integer
format: int64
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
application/xml:
schema:
$ref: '#/components/schemas/Order'
'400':
description: Invalid ID supplied
'404':
description: Order not found
delete:
tags:
- curation
summary: Delete purchase order by ID
description: For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
operationId: deleteOrder
parameters:
- name: orderId
in: path
description: ID of the order that needs to be deleted
required: true
schema:
type: integer
format: int64
responses:
'400':
description: Invalid ID supplied
'404':
description: Order not found
components:
schemas:
Curation:
type: object
properties:
id:
type: integer
format: int64
examples: [10]
curationId:
type: integer
format: int64
examples: [198772]
quantity:
type: integer
format: int32
examples: [7]
status:
type: string
description: Order Status
examples: [approved]
enum:
- placed
- approved
- delivered
complete:
type: boolean
xml:
name: order
ApiResponse:
type: object
properties:
code:
type: integer
format: int32
type:
type: string
message:
type: string
xml:
name: '##default'
requestBodies:
Curation:
description: Curation object that needs to be added
content:
application/json:
schema:
$ref:
application/xml:
schema:
$ref:
securitySchemes:
petstore_auth:
type: oauth2
flows:
implicit:
authorizationUrl:
scopes:
write:curations: modify curations in your account
read:curations: read your curations
api_key:
type: apiKey
name: api_key
in: header
