포괄적이고 정확한 API 문서를 생성하는 것은 소프트웨어 개발에서 중요하지만 종종 지루한 부분입니다. OpenAPI Specification(이전 이름: Swagger)은 RESTful API를 정의하기 위한 산업 표준으로 자리 잡았습니다. 이 표준은 소스 코드, 문서에 접근하거나 네트워크 트래픽 검사 없이도 사람과 컴퓨터 모두 서비스의 기능을 발견하고 이해할 수 있도록 기계가 읽을 수 있는 형식을 제공합니다.1
많은 프레임워크가 코드 주석(예: 독스트링)에서 OpenAPI 사양을 생성하는 플러그인을 제공하지만, 사양 생성에 대해 더 직접적이고 프로그래밍 방식의 제어가 필요한 시나리오가 있습니다. 이는 레거시 시스템, 비표준 프레임워크를 사용하거나 여러 마이크로서비스로 구성된 API에 대한 사양을 생성해야 하기 때문일 수 있습니다.
여기서 pyswagger
가 등장합니다. pyswagger
는 OpenAPI를 위한 툴킷 역할을 하는 강력한 Python 라이브러리입니다. OpenAPI 사양으로 정의된 서비스를 소비하기 위한 API 클라이언트로 자주 사용되지만, 그 진정한 힘은 사양을 프로그래밍 방식으로 구성, 조작 및 검증할 수 있는 객체 모델에 있습니다.
이 포괄적인 튜토리얼에서는 pyswagger
를 사용하여 Flask로 구축된 간단한 Python 웹 애플리케이션에 대한 완전한 OpenAPI 3.0 사양을 수동으로, 그러나 자동으로 생성하는 과정을 단계별로 살펴보겠습니다. 사양을 처음부터 하나씩 구축하여 pyswagger
의 객체가 OpenAPI 표준의 구성 요소와 직접적으로 어떻게 매핑되는지 보여줄 것입니다. 마지막에는 생성된 openapi.json
파일뿐만 아니라 애플리케이션에서 직접 제공되는 라이브 대화형 문서 UI도 갖게 될 것입니다.
최대 생산성으로 개발팀이 함께 작업할 수 있는 통합 올인원 플랫폼을 원하시나요?
Apidog는 여러분의 모든 요구사항을 충족하며, Postman을 훨씬 저렴한 가격으로 대체합니다!
파트 1: 프로젝트 환경 설정
사양 생성을 시작하기 전에 적절한 개발 환경을 설정해야 합니다. 여기에는 종속성을 관리하기 위한 격리된 Python 환경을 만들고 필요한 라이브러리를 설치하는 작업이 포함됩니다.
작업 공간 만들기 ⚙️
먼저 프로젝트 디렉토리를 만듭니다. 터미널 또는 명령 프롬프트를 열고 다음 명령을 실행합니다.Bash
# 프로젝트를 위한 새 디렉토리 생성
mkdir pyswagger-tutorial
cd pyswagger-tutorial
# Python 가상 환경 생성
# macOS/Linux에서
python3 -m venv venv
# Windows에서
python -m venv venv
가상 환경은 Python 설치와 여러 지원 파일을 포함하는 자체 포함된 디렉토리 트리입니다. 가상 환경을 사용하면 이 프로젝트에 설치하는 패키지가 다른 프로젝트에 설치된 패키지와 충돌하지 않도록 보장할 수 있습니다.
이제 가상 환경을 활성화합니다.Bash
# macOS/Linux에서
source venv/bin/activate
# Windows에서
.\venv\Scripts\activate
활성화되면 터미널 프롬프트가 가상 환경의 이름(예: (venv)
)을 표시하도록 변경되어 이제 해당 환경 내에서 작업하고 있음을 나타냅니다.
필요한 라이브러리 설치
환경이 활성화되면 이 튜토리얼에 필요한 Python 라이브러리를 설치할 수 있습니다. 사양을 구축하기 위해 pyswagger
자체, 간단한 웹 API를 만들기 위해 Flask
, 그리고 pyswagger
가 YAML 작업을 위해 사용하는 PyYAML
이 필요합니다.Bash
pip install "pyswagger[utils]" Flask PyYAML
pyswagger
를 설치할 때 [utils]
부분은 나중에 생성된 사양의 정확성을 확인하는 데 사용할 유효성 검사기와 같은 유용한 유틸리티를 포함하므로 좋은 습관입니다.
좋은 프로젝트 관리를 위해 requirements.txt
파일에 종속성을 고정하는 것이 현명합니다.Bash
pip freeze > requirements.txt
이제 requirements.txt
에는 라이브러리와 해당 특정 버전이 포함되어 있어 다른 사람들이 프로젝트를 쉽게 재현할 수 있습니다.
기본 Flask 애플리케이션 생성
이제 최소한의 Flask 애플리케이션을 만들어 보겠습니다. 이것은 문서화할 API의 기반이 될 것입니다.
프로젝트 디렉토리에 app.py
라는 새 파일을 만들고 다음 코드를 추가합니다.Python
# app.py
from flask import Flask, jsonify
# Flask 애플리케이션 초기화
app = Flask(__name__)
@app.route("/")
def index():
""" 앱이 실행 중인지 확인하는 간단한 엔드포인트입니다. """
return jsonify({"message": "API가 정상적으로 실행 중입니다!"})
if __name__ == "__main__":
# Flask 앱을 http://127.0.0.1:5000에서 실행합니다.
app.run(debug=True)
이 코드는 단일 엔드포인트를 가진 매우 간단한 웹 서버를 설정합니다. 실행하려면 가상 환경이 여전히 활성화되어 있는지 확인하고 터미널에서 다음 명령을 실행합니다.Bash
python app.py
서버가 실행 중임을 나타내는 다음과 유사한 출력이 표시되어야 합니다.
* Serving Flask app 'app'
* Debug mode: on
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
이제 웹 브라우저를 열거나 curl
과 같은 도구를 사용하여 http://127.0.0.1:5000
을 방문할 수 있습니다. JSON 응답: {"message": "API가 정상적으로 실행 중입니다!"}
가 표시되어야 합니다.
기본 환경과 애플리케이션 골격이 준비되었으므로 이제 pyswagger
의 핵심 개념에 대해 자세히 알아볼 수 있습니다.
파트 2: pyswagger
객체 모델 이해
pyswagger
를 효과적으로 사용하여 사양을 생성하려면 먼저 해당 객체 모델이 OpenAPI 문서의 구조와 어떻게 일치하는지 이해해야 합니다. OpenAPI 사양은 본질적으로 특정 스키마를 가진 큰 JSON 또는 YAML 객체입니다. pyswagger
는 이 스키마를 반영하는 Python 클래스와 객체를 제공하여 사양을 보다 직관적이고 객체 지향적인 방식으로 구축할 수 있도록 합니다.
OpenAPI 3.0 사양의 핵심 개념 📜
OpenAPI 3.0 문서에는 몇 가지 주요 최상위 필드가 있습니다.
openapi
: OpenAPI 사양 버전을 지정하는 문자열(예:'3.0.0'
)입니다.info
: API에 대한 메타데이터를 제공하는 객체입니다. 여기에는title
,version
,description
및 연락처 정보가 포함됩니다.servers
: API의 기본 URL을 정의하는 서버 객체 배열입니다.paths
: 가장 중요한 필드입니다. 이 객체는 사용 가능한 모든 API 엔드포인트(경로)와 해당 엔드포인트에서 수행할 수 있는 HTTP 작업(GET, POST, PUT, DELETE 등)을 포함합니다.components
: 사양의 다양한 부분에 대한 재사용 가능한 객체 세트를 포함하는 객체입니다. 이는 사양을 DRY(Don't Repeat Yourself)하게 유지하는 데 중요합니다. 재사용 가능한schemas
(데이터 모델),responses
,parameters
,examples
등을 정의할 수 있습니다.
OpenAPI를 pyswagger
객체로 매핑
pyswagger
는 이러한 OpenAPI 개념을 Python 객체로 깔끔하게 매핑합니다. 우리가 사용할 주요 객체를 살펴보겠습니다.
pyswagger
의 중심 객체는 App
입니다. App
인스턴스를 OpenAPI 문서의 루트라고 생각할 수 있습니다.Python
from pyswagger import App
# 사양 문서의 루트
# 버전을 지정하여 초기화하지만, URL 또는 파일에서 로드할 수도 있습니다.
root_app = App(version='3.0.0')
App
객체를 얻으면 해당 속성을 채우기 시작할 수 있으며, 이는 OpenAPI 필드와 직접적으로 일치합니다. pyswagger
는 빌더 패턴을 사용하여 유창하고 읽기 쉬운 구문을 제공합니다.
Info 및 Servers
info
및 servers
섹션은 채우기 쉽습니다.Python
# 'info' 객체 채우기
root_app.info.title = "사용자 API"
root_app.info.version = "1.0.0"
root_app.info.description = "pyswagger 튜토리얼에 사용되는 간단한 사용자 관리 API입니다."
# 'servers' 배열 채우기
# Server 객체를 생성하고 추가합니다.
server = root_app.prepare_obj('Server', {'url': 'http://127.0.0.1:5000', 'description': '로컬 개발 서버'})
root_app.servers.append(server)
Paths 및 Operations
경로는 App
객체에 정의됩니다. 새 경로를 추가한 다음 해당 경로 내에서 작업(HTTP 메서드)을 정의합니다. 각 작업은 summary
, description
, parameters
, requestBody
및 responses
와 같은 세부 정보로 구성됩니다.Python
# 경로 및 작업 정의
# 이것은 아무것도 실행하지 않습니다. 단지 객체 구조를 구축하는 것입니다.
path_item = root_app.define_path('/users')
get_op = path_item.define_op('get')
get_op.summary = "모든 사용자 목록 검색"
Components: Schemas, Parameters 및 Responses
잘 구조화된 OpenAPI 사양의 진정한 힘은 재사용 가능한 구성 요소에서 나옵니다. 응답에 나타날 때마다 "사용자" 객체의 구조를 정의하는 대신 components/schemas
에 한 번 정의한 다음 $ref
포인터를 사용하여 참조합니다. pyswagger
는 이를 우아하게 처리합니다.
Schema
: Schema
객체는 데이터 모델을 정의합니다. 해당 유형(object
, string
, integer
)과 속성을 지정할 수 있습니다.Python
# User를 위한 Schema 객체 준비
user_schema = root_app.prepare_obj('Schema', {
'type': 'object',
'properties': {
'id': {'type': 'integer', 'format': 'int64'},
'username': {'type': 'string'},
'email': {'type': 'string', 'format': 'email'}
},
'required': ['id', 'username', 'email']
})
# 재사용 가능한 구성 요소에 추가
root_app.components.schemas['User'] = user_schema
Parameter
: Parameter
객체는 단일 작업 매개변수를 정의합니다. 해당 이름, 위치(in
: 'path'
, 'query'
, 'header'
또는 'cookie'
) 및 스키마를 지정합니다.Python
# 경로에 있는 사용자 ID를 위한 Parameter 객체 준비
user_id_param = root_app.prepare_obj('Parameter', {
'name': 'user_id',
'in': 'path',
'description': '검색할 사용자의 ID',
'required': True,
'schema': {'type': 'integer'}
})
Response
: Response
객체는 특정 HTTP 상태 코드에 대한 응답의 구조를 정의합니다. 여기에는 description
과 미디어 유형(예: application/json
) 및 해당 스키마를 지정하는 content
가 포함됩니다.Python# 단일 사용자를 반환하는 200 OK 응답을 위한 Response 객체 준비 # 재사용 가능한 User 스키마를 가리키는 '$ref' 사용에 주목하세요. ok_user_response = root_app.prepare_obj('Response', { 'description': '사용자 검색 성공', 'content': { 'application/json': { 'schema': {'$ref': '#/components/schemas/User'} } } })
이 매핑을 이해하는 것이 사양 구축의 핵심입니다. 본질적으로 pyswagger
가 나중에 유효한 OpenAPI JSON 또는 YAML 파일로 직렬화할 Python 객체 그래프를 구성하는 것입니다.
파트 3: Flask로 간단한 API 구축
문서화 연습을 실용적으로 만들기 위해 문서화할 실제 API가 필요합니다. 파트 1의 간단한 Flask 앱을 사용자 목록 관리를 위한 최소한의 REST API로 확장할 것입니다. 이 API는 pyswagger
로 설명할 "진실의 원천" 역할을 할 것입니다.
간단한 "사용자" API 설계 📝
일반적인 CRUD(생성, 읽기, 업데이트, 삭제) 작업을 나타내는 네 가지 기본 엔드포인트를 구현할 것입니다.
GET /users
: 모든 사용자 목록을 검색합니다.POST /users
: 새 사용자를 생성합니다.GET /users/{user_id}
: ID로 단일 사용자를 가져옵니다.DELETE /users/{user_id}
: ID로 사용자를 삭제합니다.
단순성을 위해 인메모리 "데이터베이스"로 간단한 Python 사전을 사용할 것입니다. 실제 애플리케이션에서는 PostgreSQL 또는 MongoDB와 같은 데이터베이스 연결이 될 것입니다.
Flask 엔드포인트 구현
이제 app.py
파일을 업데이트하여 이러한 엔드포인트에 대한 로직을 포함해 보겠습니다. app.py
의 내용을 다음으로 바꿉니다.Python
# app.py
from flask import Flask, jsonify, request, abort
app = Flask(__name__)
# --- 인메모리 데이터베이스 ---
# 사용자를 저장하기 위한 간단한 사전입니다.
# 키는 user_id(정수)이고 값은 사용자 데이터(사전)입니다.
USERS_DB = {
1: {"username": "alice", "email": "alice@example.com"},
2: {"username": "bob", "email": "bob@example.com"},
3: {"username": "charlie", "email": "charlie@example.com"},
}
# 새 사용자의 자동 증가 ID를 시뮬레이션하기 위한 카운터
LAST_INSERT_ID = 3
# --- API 엔드포인트 ---
@app.route("/users", methods=["GET"])
def get_users():
""" 모든 사용자 목록을 반환합니다. """
# 사전을 ID를 포함한 사용자 객체 목록으로 변환해야 합니다.
users_list = []
for user_id, user_data in USERS_DB.items():
user = {'id': user_id}
user.update(user_data)
users_list.append(user)
return jsonify(users_list)
@app.route("/users", methods=["POST"])
def create_user():
""" 새 사용자를 생성합니다. """
global LAST_INSERT_ID
if not request.json or 'username' not in request.json or 'email' not in request.json:
abort(400, description="요청 본문에 사용자 이름 또는 이메일이 누락되었습니다.")
LAST_INSERT_ID += 1
new_user_id = LAST_INSERT_ID
new_user = {
"username": request.json["username"],
"email": request.json["email"],
}
USERS_DB[new_user_id] = new_user
# 응답에는 새로 생성된 사용자의 ID가 포함되어야 합니다.
response_user = {'id': new_user_id}
response_user.update(new_user)
return jsonify(response_user), 201
@app.route("/users/<int:user_id>", methods=["GET"])
def get_user(user_id):
""" ID로 단일 사용자를 반환합니다. """
if user_id not in USERS_DB:
abort(404, description=f"ID {user_id}를 가진 사용자를 찾을 수 없습니다.")
user_data = USERS_DB[user_id]
user = {'id': user_id}
user.update(user_data)
return jsonify(user)
@app.route("/users/<int:user_id>", methods=["DELETE"])
def delete_user(user_id):
""" ID로 사용자를 삭제합니다. """
if user_id not in USERS_DB:
abort(404, description=f"ID {user_id}를 가진 사용자를 찾을 수 없습니다.")
del USERS_DB[user_id]
# 성공적인 삭제에 대한 표준 응답은 204 No Content입니다.
return '', 204
if __name__ == "__main__":
app.run(debug=True, port=5000)
이제 python app.py
를 다시 실행하면 완전히 작동하는 (간단하지만) API를 갖게 됩니다. curl
또는 유사한 도구로 테스트할 수 있습니다.
- 모든 사용자 가져오기:
curl http://127.0.0.1:5000/users
- 특정 사용자 가져오기:
curl http://127.0.0.1:5000/users/1
- 사용자 생성:
curl -X POST -H "Content-Type: application/json" -d '{"username": "david", "email": "david@example.com"}' http://127.0.0.1:5000/users
- 사용자 삭제:
curl -X DELETE http://127.0.0.1:5000/users/3
API가 구현되었으므로 문서화 노력의 구체적인 목표를 갖게 되었습니다. 다음 단계는 pyswagger
를 사용하여 이러한 각 엔드포인트를 자세히 설명하는 것입니다.
파트 4: pyswagger
로 OpenAPI 사양 자동 생성
이것이 우리 튜토리얼의 핵심입니다. 이제 pyswagger
를 가져오고, 객체 모델을 사용하여 API 구조를 정의한 다음, 해당 구조를 완전한 openapi.json
파일로 직렬화하는 별도의 Python 스크립트를 만들 것입니다. 이 접근 방식은 사양 생성을 애플리케이션 로직과 분리하여 매우 깔끔하고 유지 관리 가능한 패턴이 될 수 있습니다.
사양 생성기 만들기
프로젝트 디렉토리에 generate_spec.py
라는 새 파일을 만듭니다. 이 스크립트는 OpenAPI 사양을 구축하고 저장하는 역할을 합니다.
단계별 사양 구축
generate_spec.py
스크립트를 하나씩 구축해 보겠습니다.
1. 가져오기 및 App
초기화
먼저 pyswagger
에서 App
객체를 가져오고 최종 파일을 덤프하는 데 도움이 되는 PyYAML
을 가져와야 합니다. 파트 2에서 논의한 것처럼 루트 App
객체를 만들고 기본 info
및 servers
섹션을 채울 것입니다.Python
# generate_spec.py
import json
from pyswagger import App
from pyswagger.contrib.client.requests import Client
# --- 1. 루트 App 객체 초기화 ---
app = App(version='3.0.0')
# --- 2. Info & Servers 섹션 채우기 ---
app.info.title = "사용자 API"
app.info.version = "1.0.0"
app.info.description = "pyswagger 튜토리얼을 위한 간단한 사용자 관리 API입니다."
server = app.prepare_obj('Server', {
'url': 'http://127.0.0.1:5000',
'description': '로컬 개발 서버'
})
app.servers.append(server)
2. 재사용 가능한 구성 요소 정의 (Schemas)
좋은 API 설계는 반복을 피합니다. User
데이터 모델을 한 번 정의하고 재사용할 것입니다. 또한 오류 응답(예: 404 Not Found)에 대한 일반적인 Error
스키마도 정의할 것입니다.
generate_spec.py
에 다음 코드를 추가합니다.Python
# --- 3. 재사용 가능한 구성 요소 정의 (Schemas) ---
# Error 응답에 대한 스키마
error_schema = app.prepare_obj('Schema', {
'type': 'object',
'properties': {
'code': {'type': 'integer', 'format': 'int32'},
'message': {'type': 'string'}
}
})
app.components.schemas['Error'] = error_schema
# 단일 User에 대한 스키마입니다. 속성이 USERS_DB 구조와 일치하는 것을 확인하세요.
user_schema = app.prepare_obj('Schema', {
'type': 'object',
'properties': {
'id': {
'type': 'integer',
'description': '사용자의 고유 식별자.',
'readOnly': True # 클라이언트는 이 값을 설정할 수 없습니다.
},
'username': {
'type': 'string',
'description': '사용자가 선택한 사용자 이름.'
},
'email': {
'type': 'string',
'description': '사용자의 이메일 주소.',
'format': 'email'
}
},
'required': ['id', 'username', 'email']
})
app.components.schemas['User'] = user_schema
# 사용자 생성을 위한 스키마 ('id' 필드는 포함되지 않음)
new_user_schema = app.prepare_obj('Schema', {
'type': 'object',
'properties': {
'username': {
'type': 'string',
'description': '사용자가 선택한 사용자 이름.'
},
'email': {
'type': 'string',
'description': '사용자의 이메일 주소.',
'format': 'email'
}
},
'required': ['username', 'email']
})
app.components.schemas['NewUser'] = new_user_schema
3. /users
엔드포인트 문서화
이제 /users
경로와 해당 두 가지 작업(GET
및 POST
)을 정의할 것입니다.
GET
의 경우 응답은User
객체의 배열입니다.POST
의 경우 요청 본문은NewUser
객체를 예상하며, 성공적인 응답은 단일User
객체(새 ID 포함)가 될 것입니다.
<!-- end list -->Python
# --- 4. 경로 문서화 ---
# -- 경로: /users --
path_users = app.define_path('/users')
# 작업: GET /users
op_get_users = path_users.define_op('get')
op_get_users.summary = "모든 사용자 나열"
op_get_users.description = "모든 사용자 객체의 JSON 배열을 반환합니다."
op_get_users.tags.append('Users')
op_get_users.responses.A('200').description = "사용자 목록."
op_get_users.responses.A('200').content.A('application/json').schema.A(
'array', items={'$ref': '#/components/schemas/User'}
)
# 작업: POST /users
op_post_users = path_users.define_op('post')
op_post_users.summary = "새 사용자 생성"
op_post_users.description = "데이터베이스에 새 사용자를 추가합니다."
op_post_users.tags.append('Users')
op_post_users.requestBody.description = "추가해야 하는 사용자 객체."
op_post_users.requestBody.required = True
op_post_users.requestBody.content.A('application/json').schema.set_ref('#/components/schemas/NewUser')
op_post_users.responses.A('201').description = "사용자가 성공적으로 생성되었습니다."
op_post_users.responses.A('201').content.A('application/json').schema.set_ref('#/components/schemas/User')
op_post_users.responses.A('400').description = "잘못된 입력 제공."
op_post_users.responses.A('400').content.A('application/json').schema.set_ref('#/components/schemas/Error')
중첩된 객체 구조를 구축하기 위한 보다 간결한 구문을 위해 set_ref
및 A
("access"의 약자) 사용에 주목하세요.
4. /users/{user_id}
엔드포인트 문서화
다음으로 단일 사용자와 상호 작용하기 위한 경로를 문서화할 것입니다. 이 경로에는 경로 매개변수 {user_id}
가 포함됩니다.
GET
의 경우 이 경로 매개변수를 정의해야 합니다. 응답은 단일User
객체 또는404
오류입니다.DELETE
의 경우에도 경로 매개변수가 필요합니다. 성공적인 응답은204 No Content
입니다.
<!-- end list -->Python
# -- 경로: /users/{user_id} --
path_user_id = app.define_path('/users/{user_id}')
# 이 경로의 모든 작업에 대해 매개변수를 한 번 정의하고 재사용할 수 있습니다.
user_id_param = app.prepare_obj('Parameter', {
'name': 'user_id',
'in': 'path',
'description': '사용자의 ID',
'required': True,
'schema': {'type': 'integer'}
})
path_user_id.parameters.append(user_id_param)
# 작업: GET /users/{user_id}
op_get_user_id = path_user_id.define_op('get')
op_get_user_id.summary = "ID로 사용자 찾기"
op_get_user_id.description = "단일 사용자를 반환합니다."
op_get_user_id.tags.append('Users')
op_get_user_id.responses.A('200').description = "성공적인 작업."
op_get_user_id.responses.A('200').content.A('application/json').schema.set_ref('#/components/schemas/User')
op_get_user_id.responses.A('404').description = "사용자를 찾을 수 없습니다."
op_get_user_id.responses.A('404').content.A('application/json').schema.set_ref('#/components/schemas/Error')
# 작업: DELETE /users/{user_id}
op_delete_user_id = path_user_id.define_op('delete')
op_delete_user_id.summary = "사용자 삭제"
op_delete_user_id.description = "데이터베이스에서 단일 사용자를 삭제합니다."
op_delete_user_id.tags.append('Users')
op_delete_user_id.responses.A('204').description = "사용자가 성공적으로 삭제되었습니다."
op_delete_user_id.responses.A('404').description = "사용자를 찾을 수 없습니다."
op_delete_user_id.responses.A('404').content.A('application/json').schema.set_ref('#/components/schemas/Error')
5. 사양 검증 및 저장
마지막으로 가장 만족스러운 단계입니다. pyswagger
에게 구성된 객체 그래프를 OpenAPI 3.0 스키마에 대해 검증하도록 요청할 것입니다. 유효하다면 JSON 파일로 덤프할 것입니다.
이 최종 코드 블록을 generate_spec.py
에 추가합니다.Python
# --- 5. 사양 검증 및 저장 ---
if __name__ == '__main__':
try:
# 생성된 사양 검증
app.validate()
print("사양이 유효합니다.")
# 사양을 JSON 파일로 저장
with open('openapi.json', 'w') as f:
f.write(app.dump_json(indent=2))
print("openapi.json이 성공적으로 생성되었습니다.")
except Exception as e:
print(f"유효성 검사 오류: {e}")
이제 generate_spec.py
파일이 완성되었습니다. 터미널에서 실행합니다.Bash
python generate_spec.py
모든 것이 올바르면 다음 출력이 표시됩니다.
사양이 유효합니다.
openapi.json이 성공적으로 생성되었습니다.
이제 프로젝트 디렉토리에 새 파일 openapi.json
이 생성됩니다. 파일을 열어 내용을 살펴보세요. Flask API를 자세하게 설명하는 완벽하게 구조화된 OpenAPI 3.0 문서가 표시될 것입니다.
파트 5: 문서 제공
openapi.json
파일을 갖는 것은 기계와 클라이언트 SDK 생성에 훌륭하지만, 인간 개발자에게는 대화형 UI가 훨씬 유용합니다. 이 마지막 파트에서는 생성된 사양을 Flask 앱에 통합하고 인기 있는 Swagger UI를 사용하여 제공할 것입니다.
사양을 Flask에 통합
먼저 Flask 앱에서 openapi.json
파일을 제공하는 엔드포인트를 만들어야 합니다. 이렇게 하면 문서화 도구가 실행 중인 API에서 직접 사양을 가져올 수 있습니다.
app.py
를 수정하여 새 라우트를 추가합니다.Python
# app.py
# ... (기존 Flask 코드 모두 유지) ...
import os
# ... ( /users, /users/{user_id} 등 모든 라우트) ...
# --- OpenAPI 사양 및 UI 제공 ---
@app.route('/api/docs/openapi.json')
def serve_openapi_spec():
""" 생성된 openapi.json 파일을 제공합니다. """
# openapi.json이 app.py와 같은 디렉토리에 있다고 가정합니다.
# 더 큰 앱에서는 파일을 찾는 더 강력한 방법이 필요할 수 있습니다.
return app.send_static_file('openapi.json')
이것이 작동하려면 Flask가 정적 파일을 어디서 찾을지 알아야 합니다. 기본적으로 static
디렉토리를 찾습니다. 하나를 만들고 openapi.json
파일을 그곳으로 이동해 보겠습니다.Bash
mkdir static
mv openapi.json static/
이제 python app.py
를 실행하고 http://127.0.0.1:5000/api/docs/openapi.json
으로 이동합니다. 사양의 원시 JSON이 표시되어야 합니다.
Swagger UI로 대화형 UI 제공 🎨
Swagger UI는 OpenAPI 호환 API에서 아름다운 문서를 동적으로 생성하는 종속성 없는 HTML,2 JavaScript 및 CSS 자산 모음입니다. Flask 애플리케이션에서 쉽게 제공할 수 있습니다.
템플릿 디렉토리 생성: Flask는 HTML 템플릿을 찾기 위해 templates
라는 디렉토리를 사용합니다.Bash
mkdir templates
Swagger UI 템플릿 생성: templates
디렉토리 안에 swagger_ui.html
이라는 새 파일을 만듭니다. 다음 HTML 코드를 붙여넣습니다. 이 코드는 공용 CDN에서 Swagger UI 자산을 로드하고 사양 파일을 로드하도록 구성합니다.HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>사용자 API - Swagger UI</title>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.17.14/swagger-ui.min.css" >
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.17.14/swagger-ui-bundle.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.17.14/swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
// Swagger3 UI 호출 영역 시작
const ui = SwaggerUIBundle({
url: "/api/docs/openapi.json", // 사양 파일의 URL
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset4
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
// Swagger UI 호출 영역 끝
window.ui = ui
}
</script>
</body>
</html>
```
Flask 라우트 추가: 마지막으로 이 HTML 템플릿을 렌더링하는 라우트를 app.py
에 추가합니다. Flask에서 render_template
를 가져와야 합니다.Python
# app.py 상단에
from flask import Flask, jsonify, request, abort, render_template
# ... (다른 모든 라우트) ...
@app.route('/api/docs/')
def serve_swagger_ui():
""" 대화형 Swagger UI 문서를 제공합니다. """
return render_template('swagger_ui.html')
모두 함께
최종 프로젝트 구조는 다음과 같아야 합니다.
pyswagger-tutorial/
├── app.py
├── generate_spec.py
├── requirements.txt
├── static/
│ └── openapi.json
├── templates/
│ └── swagger_ui.html
└── venv/
이제 최종 결과입니다. Flask 앱이 실행 중인지 확인하고 (python app.py
) 웹 브라우저를 열어 다음으로 이동합니다.
http://127.0.0.1:5000/api/docs/
API에 대한 아름답고 대화형 문서 페이지가 표시될 것입니다. 각 엔드포인트를 확장하고 정의한 스키마를 확인하며 "Try it out" 버튼을 사용하여 브라우저에서 직접 실행 중인 Flask 애플리케이션으로 실시간 요청을 보낼 수도 있습니다.
결론
이 튜토리얼에서는 빈 디렉토리에서 완전히 문서화된 API까지 여정을 거쳤습니다. pyswagger
의 객체 모델을 API 구조에 매핑하여 상세한 OpenAPI 3.0 사양을 프로그래밍 방식으로 성공적으로 구축했습니다. 메타데이터, 서버, 재사용 가능한 스키마, 경로 및 작업과 해당 매개변수 및 응답을 정의하는 방법을 살펴보았습니다.
사양 생성(generate_spec.py
)을 애플리케이션 로직(app.py
)과 분리함으로써 깔끔한 워크플로우를 만들었습니다. API를 구현한 다음 생성기를 실행하여 문서를 생성하는 것입니다. 이 프로세스는 데코레이터 기반 접근 방식보다 더 수동적이지만, 비할 데 없는 제어 및 유연성을 제공하여 복잡한 프로젝트, 레거시 코드베이스 또는 문서 표준이 엄격할 때 이상적입니다.
마지막으로, 생성된 사양과 Swagger UI 인스턴스를 제공함으로써 API 소비자를 위한 세련되고 전문적이며 매우 유용한 문서 포털을 제공했습니다. 이제 세계적 수준의 API 문서를 만들기 위한 Python 개발 도구 상자에 강력한 새 도구를 갖게 되었습니다.
최대 생산성으로 개발팀이 함께 작업할 수 있는 통합 올인원 플랫폼을 원하시나요?
Apidog는 여러분의 모든 요구사항을 충족하며, Postman을 훨씬 저렴한 가격으로 대체합니다!