SlideShare a Scribd company logo
1 of 9
Download to read offline
API 자동화문서도입기 1
API 자동화문서도입기
Tech Project 📄 API 자동화문서
상태 Not started
완료시간 0
태그
라떼는말이야….
API 명세를하나하나손으로썼다고…
요즘젊은것들은…..
라떼는말이야….
요즘젊은것들은…..
어떻게구현했냐구요?
OpenAPI란?
Swagger란?
번외) JSON보다YAML 형식이많이이용되는이유
drf에서의API 자동화문서tool
drf-spectacular를우리프로젝트에적용하기위해서는
문제를해결하기위해서는.. 작동원리를알아야한다
말은쉽지…코드로뜯어봅시다
Reference
API 자동화문서도입기 2
•⭐[Try it Out]을통해직접api를실행해볼수있습니다!
어떻게구현했냐구요?
drf-spectacular를이용했습니다
OpenAPI란?
우리가아는이Open API가아닙니다!
OpenApI Specification(OAS)를OpenAPI라고부름
RESTful API를정의된규칙에맞게API Spec를json이나yaml으로표현하는방식
예전2.0 버전까지는Swagger 2.0와같이불렸다가Swagger가OpenAPI Initiative로이관되면서, 현재3.0버전부터는OpenAPI
3.0 Specification으로칭함(여전히혼용되고있음)
Swagger란?
크게아래세가지의toolset
Swagger Codegen: 브라우저기반의편집기, OpenAPI Spec을쉽게작성할수있게도와줌
Swagger Editor: OpenAPI spec에맞게생성된Spec를수정할수있음
⭐Swagger UI : OpenAPI JSON/YAML을API 문서로렌더링
API 자동화문서도입기 3
번외) JSON보다YAML 형식이많이이용되는이유
가독성
YAML은들여쓰기와줄바꿈이가능
YAML은주석을지원하기때문에문서에설명이나메모를추가하기가용이
#JSON 형식
{
"openapi": "3.0.0",
"info": {
"title": "예시 API",
"version": "1.0.0"
},
"paths": {
"/users": {
"get": {
"summary": "모든 사용자 조회",
"responses": {
"200": {
"description": "성공",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
}
}
}
}
}
}
}
}
}
}ㅇ
# YAML 형식
openapi: 3.0.0
info:
title: 예시 API
version: 1.0.0
paths:
/users:
get:
summary: 모든 사용자 조회
responses:
200:
description: 성공
content:
application/json:
schema:
type: array
items:
type: object
properties:
id:
type: integer
name:
type: string
API 자동화문서도입기 4
drf에서의API 자동화문서tool
drf native
drf-yasg
drf-yasg — drf-yasg 1.21.6 documentation
https://drf-yasg.readthedocs.io/en/stable/
drf-spectcular
drf-spectacular — drf-spectacular documentation
https://drf-spectacular.readthedocs.io/en/latest/
drf-spectcular를선택한이유
drf-native : swagger-ui가아니어서가독성이떨어지며테스트불가. 기능상저하로거의아무도사용X
drf-yasg vs drf-spectcular
drf-yasg : OpenAPI 3.0 지원X
drf-spectcular : OpenAPI 3.0 지원O
API 자동화문서도입기 5
OpenAPI 3.0은?
멀티url 가능
⭐components를통해중복되는부분을최소화함
paths:
/users/{userId}:
get:
summary: Get a user by ID
parameters:
...
responses:
'200':
description: A single user.
content:
application/json:
schema:
type: object
properties:
id:
type: integer
name:
type: string
/users:
get:
summary: Get all users
responses:
'200':
description: A list of users.
content:
application/json:
schema:
type: array
paths:
/users/{userId}:
get:
summary: Get a user by ID
parameters:
...
responses:
'200':
description: A single user.
content:
application/json:
schema:
$ref: '#/components/schemas/User'
/users:
get:
summary: Get all users
responses:
'200':
description: A list of users.
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
components:
schemas:
User:
API 자동화문서도입기 6
items:
type: object
properties:
id:
type: integer
name:
type: string
type: object
properties:
id:
type: integer
name:
type: string
drf-spectacular를우리프로젝트에적용하기위해서는
공식문서를보고그대로하면될줄알았지…만…역시나…
- drf-spectacular에서는request 및response를serializer의schema를따라서자동으로설정해준다
우리는response를serializer로처리하지않음. output_dto를이용한다
- drf 및drf-spectacular에서는multiple serializer를지원하지않는다.
우리는output_dto를이용해한응답값에여러개의serializer data를넣고있다.
문제를해결하기위해서는.. 작동원리를알아야한다
url 획득
urlpatterns으로부터endpoint(url → view mapping)을획득
view class 분석← 이친구에서serialzier 대신DTO도찾을수있게해주고
endpoints를iterate하면서각url, method에대해서request, response를찾기
스키마생성← 이친구에서DTO의스키마를생성할수있도록해보자
위에서수집한정보를바탕으로swagger 스키마를생성함
문서화
생성된swagger 스키마를기반으로API 문서화수행
API 자동화문서도입기 7
말은쉽지…코드로뜯어봅시다
view class 분석← 이친구에서serialzier 대신DTO도찾을수있게해주고
어떻게알았냐면…며칠동안break point찍어가면서찾아봄…
drf_spectacular/openapi.py
class AutoSchema(ViewInspector):
...
def get_operation(self, path, path_regex, path_prefix, method, registry: ComponentRegistry): """ override this for custom
...
operation['responses'] = self._get_response_bodies()
...
def _get_response_bodies(self, direction='response'):
response_serializers = self.get_response_serializers()
...
def _get_request_body(self, direction='request'):
...
custom하기
REST_FRAMEWORK = {
...
'DEFAULT_SCHEMA_CLASS': 'shipdan_application.settings.base_schema.DTOSchema',
}
settings/base_schema.py
class DTOSchema(AutoSchema):
def _get_response_bodies(self, direction='response'):
response_serializers = self.get_response_serializers()
if hasattr(response_serializers, 'dto_name'):
response_serializers: BaseDTO
component = self.resolve_dto(response_serializers)
response = {200: {'content': {'application/json': {'schema': component.ref}}}}
return response
else:
response = super()._get_response_bodies(direction)
return response
def _get_request_body(self, direction='request'):
if self.method not in ('PUT', 'PATCH', 'POST'):
return None
request_serializers = self.get_request_serializer()
if hasattr(request_serializers, 'dto_name'):
request_serializers: BaseDTO
component = self.resolve_dto(request_serializers)
request = {'content': {'application/json': {'schema': component.ref}}}
return request
else:
request = super()._get_request_body(direction)
return request
def resolve_dto(self, dto,) -> ResolvedComponent:
component = ResolvedComponent(
name=dto.dto_name,
type=ResolvedComponent.SCHEMA,
object=dto,
)
if component not in self.registry:
dto.schema_render(self)
return self.registry[component]
API 자동화문서도입기 8
dtos/base.py
class BaseDTO(metaclass=DTOMeta)
...
@classmethod
def schema_render(cls, auto_schema: Optional['DTOSchema'] = None):
responses = {}
component = ResolvedComponent(
name=cls.dto_name,
type=ResolvedComponent.SCHEMA,
object=cls,
)
if component in auto_schema.registry:
# 이거면 맨 처음이 아님
return auto_schema.registry[component].ref
for key, val in cls.dto_fields.items():
responses[key] = build_type(val, auto_schema)
component = ResolvedComponent(
name=cls.dto_name,
type=ResolvedComponent.SCHEMA,
object=cls,
schema={'type': 'object', 'properties': responses}
)
auto_schema.registry.register(component)
return auto_schema.registry[component].ref
dtos/base.py
def build_type(schema, auto_schema: Optional['DTOSchema'] = None):
openapi_type_mapping = get_openapi_type_mapping()
origin_schema = typing.get_origin(schema) # typing을 쓰고 있기 때문에
if hasattr(schema, 'dto_fields'):
val: BaseDTO
return schema.schema_render(auto_schema)
elif origin_schema is Union:
return build_union_type(schema, auto_schema)
elif origin_schema is list:
return build_array_type(schema, auto_schema)
elif origin_schema is dict:
return openapi_type_mapping[PYTHON_TYPE_MAPPING[schema.__origin__]]
elif type(schema) is ForwardRef:
return build_forward_value(schema, auto_schema)
else:
return openapi_type_mapping[PYTHON_TYPE_MAPPING[schema]]
def build_array_type(schema, auto_schema: Optional['DTOSchema'] = None):
schema = typing.get_args(schema)[0]
return {'type': 'array', 'items': build_type(schema, auto_schema)}
def build_union_type(schema, auto_schema: Optional['DTOSchema'] = None):
responses = {}
union_args: tuple = typing.get_args(schema)
if type(None) in union_args:
child_val = list(set(union_args) - {type(None)})[0]
responses['required'] = False
else:
child_val = union_args[0]
a = build_type(child_val, auto_schema)
return {**responses, **a}
def build_forward_value(schema: ForwardRef, auto_schema: Optional['DTOSchema'] = None):
try:
_schema = schema.__forward_value__
if _schema is None:
_schema = _DTODict[schema.__forward_arg__]
if _schema is None:
raise Exception()
return build_type(_schema, auto_schema)
except:
'''warning 아직 정의되지 않은 forward value입니다.'''
return {'type': schema.__forward_arg__}
Reference
API 자동화문서도입기 9
Django Rest Framework API Document Generator (feat. drf-spectacular)
drf-yasg의단점그리고Open API Specification 3.0
https://techblog.yogiyo.co.kr/django-rest-framework-api-document-generator-feat-drf-spectacular-585fca
bec404
https://swagger.io/blog/news/whats-new-in-openapi-3-0/

More Related Content

Similar to API 자동화 문서 도입기.pdf

070517 Jena
070517 Jena070517 Jena
070517 Jena
yuhana
 
Build web application by express
Build web application by expressBuild web application by express
Build web application by express
Shawn Meng
 
DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)
Oleg Zinchenko
 
Dependency Management with RequireJS
Dependency Management with RequireJSDependency Management with RequireJS
Dependency Management with RequireJS
Aaronius
 

Similar to API 자동화 문서 도입기.pdf (20)

070517 Jena
070517 Jena070517 Jena
070517 Jena
 
PHP-03-Functions.ppt
PHP-03-Functions.pptPHP-03-Functions.ppt
PHP-03-Functions.ppt
 
PHP-03-Functions.ppt
PHP-03-Functions.pptPHP-03-Functions.ppt
PHP-03-Functions.ppt
 
Webinar: Zend framework Getting to grips (ZF1)
Webinar: Zend framework Getting to grips (ZF1)Webinar: Zend framework Getting to grips (ZF1)
Webinar: Zend framework Getting to grips (ZF1)
 
Going crazy with Node.JS and CakePHP
Going crazy with Node.JS and CakePHPGoing crazy with Node.JS and CakePHP
Going crazy with Node.JS and CakePHP
 
Build web application by express
Build web application by expressBuild web application by express
Build web application by express
 
Stop the noise! - Introduction to the JSON:API specification in Drupal
Stop the noise! - Introduction to the JSON:API specification in DrupalStop the noise! - Introduction to the JSON:API specification in Drupal
Stop the noise! - Introduction to the JSON:API specification in Drupal
 
iOS Swift application architecture
iOS Swift application architectureiOS Swift application architecture
iOS Swift application architecture
 
Angular Intermediate
Angular IntermediateAngular Intermediate
Angular Intermediate
 
Effectively Testing Services - Burlington Ruby Conf
Effectively Testing Services - Burlington Ruby ConfEffectively Testing Services - Burlington Ruby Conf
Effectively Testing Services - Burlington Ruby Conf
 
DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)
 
Python magicmethods
Python magicmethodsPython magicmethods
Python magicmethods
 
Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)
Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)
Kicking off with Zend Expressive and Doctrine ORM (PHPNW2016)
 
Zend framework: Getting to grips (ZF1)
Zend framework: Getting to grips (ZF1)Zend framework: Getting to grips (ZF1)
Zend framework: Getting to grips (ZF1)
 
Oops in PHP
Oops in PHPOops in PHP
Oops in PHP
 
Aspects of love slideshare
Aspects of love slideshareAspects of love slideshare
Aspects of love slideshare
 
Performance tuning with zend framework
Performance tuning with zend frameworkPerformance tuning with zend framework
Performance tuning with zend framework
 
Dependency Management with RequireJS
Dependency Management with RequireJSDependency Management with RequireJS
Dependency Management with RequireJS
 
Djangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 Minutes
Djangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 MinutesDjangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 Minutes
Djangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 Minutes
 
Android networking-2
Android networking-2Android networking-2
Android networking-2
 

Recently uploaded

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Recently uploaded (20)

Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 

API 자동화 문서 도입기.pdf

  • 1. API 자동화문서도입기 1 API 자동화문서도입기 Tech Project 📄 API 자동화문서 상태 Not started 완료시간 0 태그 라떼는말이야…. API 명세를하나하나손으로썼다고… 요즘젊은것들은….. 라떼는말이야…. 요즘젊은것들은….. 어떻게구현했냐구요? OpenAPI란? Swagger란? 번외) JSON보다YAML 형식이많이이용되는이유 drf에서의API 자동화문서tool drf-spectacular를우리프로젝트에적용하기위해서는 문제를해결하기위해서는.. 작동원리를알아야한다 말은쉽지…코드로뜯어봅시다 Reference
  • 2. API 자동화문서도입기 2 •⭐[Try it Out]을통해직접api를실행해볼수있습니다! 어떻게구현했냐구요? drf-spectacular를이용했습니다 OpenAPI란? 우리가아는이Open API가아닙니다! OpenApI Specification(OAS)를OpenAPI라고부름 RESTful API를정의된규칙에맞게API Spec를json이나yaml으로표현하는방식 예전2.0 버전까지는Swagger 2.0와같이불렸다가Swagger가OpenAPI Initiative로이관되면서, 현재3.0버전부터는OpenAPI 3.0 Specification으로칭함(여전히혼용되고있음) Swagger란? 크게아래세가지의toolset Swagger Codegen: 브라우저기반의편집기, OpenAPI Spec을쉽게작성할수있게도와줌 Swagger Editor: OpenAPI spec에맞게생성된Spec를수정할수있음 ⭐Swagger UI : OpenAPI JSON/YAML을API 문서로렌더링
  • 3. API 자동화문서도입기 3 번외) JSON보다YAML 형식이많이이용되는이유 가독성 YAML은들여쓰기와줄바꿈이가능 YAML은주석을지원하기때문에문서에설명이나메모를추가하기가용이 #JSON 형식 { "openapi": "3.0.0", "info": { "title": "예시 API", "version": "1.0.0" }, "paths": { "/users": { "get": { "summary": "모든 사용자 조회", "responses": { "200": { "description": "성공", "content": { "application/json": { "schema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" } } } } } } } } } } } }ㅇ # YAML 형식 openapi: 3.0.0 info: title: 예시 API version: 1.0.0 paths: /users: get: summary: 모든 사용자 조회 responses: 200: description: 성공 content: application/json: schema: type: array items: type: object properties: id: type: integer name: type: string
  • 4. API 자동화문서도입기 4 drf에서의API 자동화문서tool drf native drf-yasg drf-yasg — drf-yasg 1.21.6 documentation https://drf-yasg.readthedocs.io/en/stable/ drf-spectcular drf-spectacular — drf-spectacular documentation https://drf-spectacular.readthedocs.io/en/latest/ drf-spectcular를선택한이유 drf-native : swagger-ui가아니어서가독성이떨어지며테스트불가. 기능상저하로거의아무도사용X drf-yasg vs drf-spectcular drf-yasg : OpenAPI 3.0 지원X drf-spectcular : OpenAPI 3.0 지원O
  • 5. API 자동화문서도입기 5 OpenAPI 3.0은? 멀티url 가능 ⭐components를통해중복되는부분을최소화함 paths: /users/{userId}: get: summary: Get a user by ID parameters: ... responses: '200': description: A single user. content: application/json: schema: type: object properties: id: type: integer name: type: string /users: get: summary: Get all users responses: '200': description: A list of users. content: application/json: schema: type: array paths: /users/{userId}: get: summary: Get a user by ID parameters: ... responses: '200': description: A single user. content: application/json: schema: $ref: '#/components/schemas/User' /users: get: summary: Get all users responses: '200': description: A list of users. content: application/json: schema: type: array items: $ref: '#/components/schemas/User' components: schemas: User:
  • 6. API 자동화문서도입기 6 items: type: object properties: id: type: integer name: type: string type: object properties: id: type: integer name: type: string drf-spectacular를우리프로젝트에적용하기위해서는 공식문서를보고그대로하면될줄알았지…만…역시나… - drf-spectacular에서는request 및response를serializer의schema를따라서자동으로설정해준다 우리는response를serializer로처리하지않음. output_dto를이용한다 - drf 및drf-spectacular에서는multiple serializer를지원하지않는다. 우리는output_dto를이용해한응답값에여러개의serializer data를넣고있다. 문제를해결하기위해서는.. 작동원리를알아야한다 url 획득 urlpatterns으로부터endpoint(url → view mapping)을획득 view class 분석← 이친구에서serialzier 대신DTO도찾을수있게해주고 endpoints를iterate하면서각url, method에대해서request, response를찾기 스키마생성← 이친구에서DTO의스키마를생성할수있도록해보자 위에서수집한정보를바탕으로swagger 스키마를생성함 문서화 생성된swagger 스키마를기반으로API 문서화수행
  • 7. API 자동화문서도입기 7 말은쉽지…코드로뜯어봅시다 view class 분석← 이친구에서serialzier 대신DTO도찾을수있게해주고 어떻게알았냐면…며칠동안break point찍어가면서찾아봄… drf_spectacular/openapi.py class AutoSchema(ViewInspector): ... def get_operation(self, path, path_regex, path_prefix, method, registry: ComponentRegistry): """ override this for custom ... operation['responses'] = self._get_response_bodies() ... def _get_response_bodies(self, direction='response'): response_serializers = self.get_response_serializers() ... def _get_request_body(self, direction='request'): ... custom하기 REST_FRAMEWORK = { ... 'DEFAULT_SCHEMA_CLASS': 'shipdan_application.settings.base_schema.DTOSchema', } settings/base_schema.py class DTOSchema(AutoSchema): def _get_response_bodies(self, direction='response'): response_serializers = self.get_response_serializers() if hasattr(response_serializers, 'dto_name'): response_serializers: BaseDTO component = self.resolve_dto(response_serializers) response = {200: {'content': {'application/json': {'schema': component.ref}}}} return response else: response = super()._get_response_bodies(direction) return response def _get_request_body(self, direction='request'): if self.method not in ('PUT', 'PATCH', 'POST'): return None request_serializers = self.get_request_serializer() if hasattr(request_serializers, 'dto_name'): request_serializers: BaseDTO component = self.resolve_dto(request_serializers) request = {'content': {'application/json': {'schema': component.ref}}} return request else: request = super()._get_request_body(direction) return request def resolve_dto(self, dto,) -> ResolvedComponent: component = ResolvedComponent( name=dto.dto_name, type=ResolvedComponent.SCHEMA, object=dto, ) if component not in self.registry: dto.schema_render(self) return self.registry[component]
  • 8. API 자동화문서도입기 8 dtos/base.py class BaseDTO(metaclass=DTOMeta) ... @classmethod def schema_render(cls, auto_schema: Optional['DTOSchema'] = None): responses = {} component = ResolvedComponent( name=cls.dto_name, type=ResolvedComponent.SCHEMA, object=cls, ) if component in auto_schema.registry: # 이거면 맨 처음이 아님 return auto_schema.registry[component].ref for key, val in cls.dto_fields.items(): responses[key] = build_type(val, auto_schema) component = ResolvedComponent( name=cls.dto_name, type=ResolvedComponent.SCHEMA, object=cls, schema={'type': 'object', 'properties': responses} ) auto_schema.registry.register(component) return auto_schema.registry[component].ref dtos/base.py def build_type(schema, auto_schema: Optional['DTOSchema'] = None): openapi_type_mapping = get_openapi_type_mapping() origin_schema = typing.get_origin(schema) # typing을 쓰고 있기 때문에 if hasattr(schema, 'dto_fields'): val: BaseDTO return schema.schema_render(auto_schema) elif origin_schema is Union: return build_union_type(schema, auto_schema) elif origin_schema is list: return build_array_type(schema, auto_schema) elif origin_schema is dict: return openapi_type_mapping[PYTHON_TYPE_MAPPING[schema.__origin__]] elif type(schema) is ForwardRef: return build_forward_value(schema, auto_schema) else: return openapi_type_mapping[PYTHON_TYPE_MAPPING[schema]] def build_array_type(schema, auto_schema: Optional['DTOSchema'] = None): schema = typing.get_args(schema)[0] return {'type': 'array', 'items': build_type(schema, auto_schema)} def build_union_type(schema, auto_schema: Optional['DTOSchema'] = None): responses = {} union_args: tuple = typing.get_args(schema) if type(None) in union_args: child_val = list(set(union_args) - {type(None)})[0] responses['required'] = False else: child_val = union_args[0] a = build_type(child_val, auto_schema) return {**responses, **a} def build_forward_value(schema: ForwardRef, auto_schema: Optional['DTOSchema'] = None): try: _schema = schema.__forward_value__ if _schema is None: _schema = _DTODict[schema.__forward_arg__] if _schema is None: raise Exception() return build_type(_schema, auto_schema) except: '''warning 아직 정의되지 않은 forward value입니다.''' return {'type': schema.__forward_arg__} Reference
  • 9. API 자동화문서도입기 9 Django Rest Framework API Document Generator (feat. drf-spectacular) drf-yasg의단점그리고Open API Specification 3.0 https://techblog.yogiyo.co.kr/django-rest-framework-api-document-generator-feat-drf-spectacular-585fca bec404 https://swagger.io/blog/news/whats-new-in-openapi-3-0/