OpenAPI를 사용한 백엔드 API 설계 및 테스트
Grace Collins
Solutions Engineer · Leapcell

소개
빠르게 발전하는 소프트웨어 개발 환경에서 API는 서로 다른 시스템 간의 원활한 통신을 촉진하는 현대 애플리케이션의 기반이 되었습니다. 이러한 애플리케이션이 복잡해짐에 따라 API 일관성, 문서화 및 테스트를 관리하는 것은 상당한 과제가 됩니다. 기존의 접근 방식은 종종 동기화되지 않은 문서, 힘든 수동 테스트 및 프런트엔드와 백엔드 팀 간의 의사소통 단절로 이어집니다. 여기서 종종 Swagger와 동의어인 OpenAPI 사양이 판도를 바꾸는 요소로 등장합니다. REST API에 대한 보편적이고 언어에 구애받지 않는 인터페이스 설명을 제공함으로써 OpenAPI는 개발자가 전례 없는 명확성과 효율성으로 API를 정의, 설계 및 소비할 수 있도록 지원합니다. 이 글에서는 OpenAPI가 백엔드 API 설계 및 테스트 프로세스를 어떻게 주도하여 반응적인 작업에서 개발 수명 주기의 능동적이고 필수적인 부분으로 변모시킬 수 있는지 자세히 살펴봅니다.
핵심 개념 이해
실제 구현에 들어가기 전에 OpenAPI와 관련된 주요 용어에 대한 일반적인 이해를 확립해 보겠습니다.
- API (Application Programming Interface): 서로 다른 애플리케이션이 서로 통신할 수 있도록 하는 정의된 규칙 세트입니다. 백엔드 목적을 위해 우리는 일반적으로 네트워크 애플리케이션에 대한 아키텍처 제약 조건을 따르고 일반적으로 HTTP 메서드를 사용하는 RESTful API에 중점을 둡니다.
- OpenAPI 사양 (OAS): RESTful API에 대한 표준화된 언어에 구애받지 않는 인터페이스 설명입니다. 이를 통해 사람과 컴퓨터 모두 소스 코드나 추가 문서에 액세스하지 않고도 서비스의 기능을 검색하고 이해할 수 있습니다. YAML 또는 JSON 형식으로 작성되는 경우가 많습니다.
- Swagger: 역사적으로 Swagger는 OpenAPI 사양을 중심으로 구축된 일련의 오픈 소스 도구, 즉 대화형 API 문서화를 위한 Swagger UI, API 설계를 위한 Swagger Editor, 서버 스텁 및 클라이언트 SDK 생성을 위한 Swagger Codegen을 지칭했습니다. "Swagger"는 종종 사양 자체를 지칭하는 데 사용되지만, 사양은 Linux Foundation에 기증되어 "OpenAPI 사양"으로 이름이 변경되었습니다.
- API 우선 설계: 구현 전에 API를 설계하고 지정하는 접근 방식입니다. 이는 코드 우선 또는 데이터베이스 우선 접근 방식과 대조되며 계약 기반 개발 프로세스를 장려합니다.
- 서버 스텁: OpenAPI 사양에서 생성된 기본 서버 측 구현으로, 실제 비즈니스 로직으로 채울 수 있는 API 엔드포인트에 대한 상용구 코드를 제공합니다.
- 클라이언트 SDK (Software Development Kit): OpenAPI 사양에서 생성된 코드 라이브러리로, 클라이언트(예: 프런트엔드 애플리케이션)가 HTTP 요청 세부 정보를 추상화하여 API와 쉽게 상호 작용할 수 있도록 합니다.
OpenAPI를 통한 설계 주도
API 설계에 OpenAPI를 사용하는 기본 원칙은 API 우선 개발입니다. 코드를 작성하고 문서를 작성하는 대신 먼저 OpenAPI 사양을 사용하여 API 계약을 정의합니다.
원칙: API 우선 개발
API 우선 접근 방식에서 OpenAPI 문서는 단일 진실 공급원이 됩니다. 팀은 이 사양에 대해 협력하여 다음을 정의합니다.
- 엔드포인트 및 경로: 다른 리소스에 액세스하기 위한 URL(예: /users,/products/{id}).
- HTTP 메서드: 해당 리소스에 대해 수행할 수 있는 작업(예: GET,POST,PUT,DELETE).
- 요청/응답 스키마: API로 보내거나 API에서 받은 데이터의 구조 및 데이터 유형으로, 종종 JSON 스키마를 사용하여 정의됩니다.
- 매개변수: 각 작업(경로, 쿼리, 헤더, 쿠키)에 필요한 입력.
- 인증 및 권한 부여: 사용되는 보안 체계(예: API 키, OAuth2).
- 오류 응답: 다양한 시나리오에 대한 표준화된 오류 형식.
구현: Swagger Editor를 사용한 설계
Swagger Editor와 같은 도구를 사용하면 개발자가 대화형으로 OpenAPI 사양을 작성할 수 있으며, 실시간 유효성 검사 및 생성된 문서 미리보기를 제공합니다.
예시: 간단한 사용자 API
사용자 관리를 위한 기본 API를 설계해 보겠습니다.
# user-api.yaml openapi: 3.0.0 info: title: User Management API version: 1.0.0 description: API for managing user accounts. servers: - url: http://localhost:8080/api/v1 description: Local Development Server paths: /users: get: summary: Retrieve a list of users operationId: listUsers parameters: - name: limit in: query description: How many items to return at one time (max 100) required: false schema: type: integer format: int32 responses: '200': description: A paged array of users content: application/json: schema: type: array items: $ref: '#/components/schemas/User' default: description: unexpected error content: application/json: schema: $ref: '#/components/schemas/Error' post: summary: Create a new user operationId: createUser requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UserCreationRequest' responses: '201': description: User created successfully content: application/json: schema: $ref: '#/components/schemas/User' default: description: unexpected error content: application/json: schema: $ref: '#/components/schemas/Error' /users/{userId}: get: summary: Info for a specific user operationId: showUserById parameters: - name: userId in: path required: true description: The ID of the user to retrieve schema: type: string responses: '200': description: Expected response to a valid request content: application/json: schema: $ref: '#/components/schemas/User' '404': description: User not found content: application/json: schema: $ref: '#/components/schemas/Error' default: description: unexpected error content: application/json: schema: $ref: '#/components/schemas/Error' components: schemas: User: type: object required: - id - name properties: id: type: string format: uuid example: d290f1ee-6c54-4b01-90e6-d701748f0851 name: type: string example: Alice email: type: string format: email example: alice@example.com UserCreationRequest: type: object required: - name - email properties: name: type: string example: Bob email: type: string format: email example: bob@example.com Error: type: object required: - code - message properties: code: type: integer format: int32 message: type: string
이 YAML 파일은 사용자 API를 정확하게 정의합니다. 프런트엔드 개발자는 이 계약을 바탕으로 즉시 UI를 구축할 수 있으며, 어떤 요청을 보내야 하고 어떤 응답을 기대해야 하는지 정확히 알 수 있습니다. 백엔드 개발자는 이 사양을 사용하여 구현을 주도할 수 있습니다.
애플리케이션: 코드 생성
OpenAPI 사양이 최종 확정되면 Swagger Codegen과 같은 도구를 사용하여 서버 스텁과 클라이언트 SDK를 생성할 수 있습니다.
- 백엔드 (서버 스텁 생성): Spring Boot, Node.js(Express) 또는 Flask와 같은 백엔드 프레임워크의 경우 Codegen은 컨트롤러 인터페이스, 모델 클래스 및 기본 라우팅까지 생성할 수 있습니다. 개발자는 생성된 구조 내에서 비즈니스 로직을 채웁니다. 이렇게 하면 구현이 정의된 API 계약을 엄격하게 준수합니다.
# Spring Boot 서버 스텁을 위한 openapi-generator-cli 예시 npx @openapitools/openapi-generator-cli generate \ -i user-api.yaml \ -g spring \ -o ./generated-server \ --additional-properties packageName=com.example.userapi
이 명령은 구현 준비가 된 UserController 인터페이스, User 모델 클래스 등을 갖춘 Spring Boot 프로젝트를 생성합니다.
- 프런트엔드 (클라이언트 SDK 생성): React, Angular 또는 모바일 앱과 같은 프런트엔드 프레임워크의 경우 Codegen은 API 호출을 캡슐화하는 클라이언트 측 라이브러리를 생성할 수 있습니다. 이렇게 하면 수동 HTTP 요청 구성 및 구문 분석이 제거되어 오류가 줄고 개발 시간이 절약됩니다.
# TypeScript 클라이언트를 위한 openapi-generator-cli 예시 npx @openapitools/openapi-generator-cli generate \ -i user-api.yaml \ -g typescript-axios \ -o ./generated-client
이렇게 생성된 TypeScript 클라이언트는 프런트엔드 개발자가 가져와 사용할 수 있습니다: api.user.listUsers({limit: 10}).
OpenAPI를 통한 테스트 주도
OpenAPI 사양은 문서화 및 설계뿐만 아니라 자동화된 API 테스트를 위한 강력한 자산입니다.
원칙: 계약 테스트 및 자동화된 유효성 검사
OpenAPI 문서는 테스트 기준으로 사용됩니다. 모든 API 구현은 이 계약을 준수해야 합니다. 이를 통해 다음을 수행할 수 있습니다.
- 스키마 유효성 검사: 요청 본문 및 응답 본문이 정의된 JSON 스키마를 준수하는지 확인합니다.
- 엔드포인트 범위: 정의된 모든 엔드포인트가 올바르게 응답하는지 확인합니다.
- 동작 테스트: 사양을 기반으로 유효한 입력, 엣지 케이스 및 오류 조건을 포함한 다양한 시나리오를 다루는 테스트 사례를 작성합니다.
구현: 전문 도구를 사용한 테스트
OpenAPI를 자동화된 테스트에 사용하는 여러 도구가 있습니다.
- 
Postman/Insomnia: 이러한 인기 있는 API 클라이언트는 OpenAPI 사양을 가져와 요청 컬렉션을 생성할 수 있어 수동 및 자동화된 테스트가 훨씬 쉬워집니다. 그런 다음 스키마에 대한 응답을 유효성 검사하는 어설션을 추가할 수 있습니다. 
- 
Dredd (Node.js용) / Schemathesis (Python용): 이러한 도구는 OpenAPI 사양을 직접 읽고 API 구현을 이에 대해 테스트합니다. 스키마 정의를 기반으로 테스트 사례를 자동으로 생성하고 응답을 유효성 검사할 수 있습니다. 예시: Schemathesis를 사용한 테스트 (Python 백엔드) Flask를 사용하는 Python으로 사용자 API가 구현되었다고 가정해 보겠습니다. # app.py (최소 Flask 앱 예시) from flask import Flask, jsonify, request import uuid app = Flask(__name__) users_db = {} # 인메모리 저장소 @app.route('/api/v1/users', methods=['GET']) def list_users(): limit = request.args.get('limit', type=int, default=100) return jsonify(list(users_db.values())[:limit]) @app.route('/api/v1/users', methods=['POST']) def create_user(): data = request.json if not data or 'name' not in data or 'email' not in data: return jsonify({"code": 400, "message": "Missing name or email"}), 400 new_user = { "id": str(uuid.uuid4()), "name": data['name'], "email": data['email'] } users_db[new_user['id']] = new_user return jsonify(new_user), 201 @app.route('/api/v1/users/<user_id>', methods=['GET']) def show_user_by_id(user_id): user = users_db.get(user_id) if user: return jsonify(user), 200 return jsonify({"code": 404, "message": "User not found"}), 404 if __name__ == '__main__': app.run(debug=True, port=8080)schemathesis로 이 Flask 애플리케이션을 테스트하려면:# 먼저 schemathesis 설치 pip install schemathesis flask gunicorn # Flask 앱을 app.py로 저장하고 실행 gunicorn -b 127.0.0.1:8080 app:app & # 그런 다음 실행 중인 API와 OpenAPI 사장에 대해 schemathesis 실행 schemathesis run -H "Accept: application/json" --base-url="http://127.0.0.1:8080/api/v1" user-api.yamlschemathesis는 스키마 위반, 처리되지 않은 오류 및 API 불일치를 찾기 위해 수천 건의 요청을 보냅니다.user-api.yaml에 정의된 구조 및 형식에 따라 다양한 입력 값을 자동으로 생성하여 API를 스트레스 테스트합니다.
- 
특정 프레임워크 통합: 많은 백엔드 프레임워크에서 통합을 제공합니다. 예를 들어 Spring Boot에서는 springdoc-openapi가 주석에서openapi.json을 생성할 수 있으며, 그런 다음 스키마 유효성 검사와 함께 REST Assured와 같은 도구를 사용할 수 있습니다. 또는 코드 생성을 지원하는 프레임워크의 경우 생성된 DTO를 단위 및 통합 테스트에서 직접 사용하여 유형 안전성 및 직렬화 일치를 보장할 수 있습니다.
애플리케이션: 지속적 통합 및 배포 (CI/CD)
OpenAPI 기반 테스트를 CI/CD 파이프라인에 통합하면 모든 코드 변경 사항이 API 계약에 대해 검증되도록 보장합니다.
- 커밋 전 훅/푸시 전 훅: OpenAPI 사양 자체의 구문 정확성 및 모범 사례를 검증합니다.
- 빌드 파이프라인: 클라이언트 SDK 및 서버 스텁을 자동으로 생성합니다. 배포된 (또는 모의) API 버전에 대해 자동 계약 테스트(schemathesis, Dredd)를 실행합니다.
- 배포 게이트: 계약 테스트가 실패하면 빌드를 실패시켜 규정을 준수하지 않는 API가 배포되는 것을 방지합니다.
이 강력한 테스트 방법론은 통합 문제를 일으킬 위험을 크게 줄이면서 중단 변경 사항을 조기에 감지하고 일관성을 시행합니다.
결론
OpenAPI 사양은 API 개발을 임시 작업 집합에서 구조화된 계약 기반 프로세스로 변환합니다. 설계를 주도하는 데 사용함으로써 단일 진실 공급원을 설정하여 병렬 개발, 간소화된 의사소통 및 코드 생성을 통한 빠른 프로토타이핑을 가능하게 합니다. 또한 테스트 단계에 OpenAPI를 통합하면 개발자가 계약 유효성 검사 및 포괄적인 동작 테스트를 자동화하여 API 품질 및 정의된 표준 준수를 보장할 수 있습니다. OpenAPI 우선 접근 방식을 채택하면 전체 API 수명 주기에 걸쳐 협업, 효율성 및 안정성을 크게 향상시킵니다. 본질적으로 OpenAPI는 설계와 구현 간의 격차를 해소하여 개발자가 확신을 가지고 강력하고 유지 관리가 가능하며 잘 문서화된 API를 구축할 수 있도록 합니다.