SlideShare a Scribd company logo
PyCon Korea 2019
AITRICS
REST API
5 

Python backend app 

Flask 2 Django
●REST API 

●OpenAPI Specification

●Python Web Applications & OpenAPI Specification

●Django API 

●Flask API
REST API
REST API ?
HTTP
METHODS
https://api.example.com/speakers https://api.example.com/speakers/1
GET 1
POST -
PUT
request body
request body field null
1 request body
request body field null
PATCH
request body
request body field
1 request body
request body field
DELETE 1
OpenAPI Specification Python Web Apps & OAS Django FlaskREST API
Representational State Transfer
( API )
REST API
OpenAPI Specification Python Web Apps & OAS Django FlaskREST API
●API , 

●Host, port

● 

●URI

●URI HTTP method 

● request header, body

● response status code, body
REST API
OpenAPI Specification Python Web Apps & OAS Django FlaskREST API
REST API
OpenAPI Specification Python Web Apps & OAS Django FlaskREST API
..



● ..

● 

●
REST API
OpenAPI Specification Python Web Apps & OAS Django FlaskREST API
OpenAPI Specification
RESTful API 

JSON, YAML 

API , / 

Swagger OpenAPI Initiative
OpenAPI Specification
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md
REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
API 

toolset 

●Swagger Codegen

●Swagger Editor

●Swagger UI

Swagger UI
●OpenAPI JSON/YAML 

API
Swagger?
https://petstore.swagger.io/
REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
API 

toolset 

●Swagger Codegen

●Swagger Editor

●Swagger UI

Swagger UI
●OpenAPI JSON/YAML 

API
Swagger?
https://petstore.swagger.io/
REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
API 

toolset 

●Swagger Codegen

●Swagger Editor

●Swagger UI

Swagger UI
●OpenAPI JSON/YAML 

API
Swagger?
https://petstore.swagger.io/
REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
API 

toolset 

●Swagger Codegen

●Swagger Editor

●Swagger UI

Swagger UI
●OpenAPI JSON/YAML 

API
Swagger?
https://petstore.swagger.io/
REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
API 

toolset 

●Swagger Codegen

●Swagger Editor

●Swagger UI

Swagger UI
●OpenAPI JSON/YAML 

API
Swagger?
REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
https://petstore.swagger.io/
title: Sample PyCON speaker API

description: This is a sample server for a PyCON speaker management.

termsOfService: http://example.com/terms/

contact:

name: API Support

url: http://www.example.com/support

email: support@example.com

license:

name: MIT

version: 1.0.1
OpenAPI Specification YAML
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md
REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
servers:

- url: https://pycon-speaker.com:{port}/{basePath}

description: The production API server

variables:

port:

enum:

- '443'

- '8443'

default: '8443'

description: 8443 is for demo.

basePath:

default: v2
OpenAPI Specification YAML
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md
REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
paths:

/speakers:

get:

description: Returns all speakers from the system that the user has access to

responses:

'200':

description: A list of speakers.

content:

application/json:

schema:

type: array

items:

$ref: '#/components/schemas/Speaker'
OpenAPI Specification YAML
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md
REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
components:

schemas:

Speaker:

required:

- id

- email

properties:

id:

type: integer

format: int64

email:

type: string

name:

type: string

OpenAPI Specification YAML
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md
REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
OpenAPI Specification YAML
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md
REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
OpenAPI Specification

JSON / YAML
APISwagger UI
paths:

/speakers:

get:

description: Returns all speakers from the system
that the user has access to

responses:

'200':

description: A list of speakers.

content:

application/json:

schema:

type: array

items:

$ref: '#/components/schemas/Speaker'
Python Web Application & 

OpenAPI Specification
Generating OpenAPI YAML
Web Application Server
●Server information

○Base URL, port, ...

●Routing information

○ path 

●Request params

●Response schema
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
Generating OpenAPI YAML
servers:

- url: https://pycon-speaker.com:{port}/{basePath}

description: The production API server

variables:

port:

enum:

- '443'

- '8443'

default: '8443'

description: 8443 is for demo.

basePath:

default: v2
Web Application Server
●Server information

○Routing information

■ Request params

■ Response schema
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
Generating OpenAPI YAML
paths:

/speakers:

get:

description: Returns all speakers

responses:

'200':

description: A list of speakers.

content:

application/json:

schema:

type: array

items:

$ref: '#/components/schemas/Speaker'
Web Application Server
●Server information

○Routing information

■ Request params

■ Response schema
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
Generating OpenAPI YAML
paths:

/speakers:

get:

description: Returns all speakers

responses:

'200':

description: A list of speakers.

content:

application/json:

schema:

type: array

items:

$ref: '#/components/schemas/Speaker'
Web Application Server
●Server information

○Routing information

■ Request params

■ Response schema
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
Generating OpenAPI YAML
paths:

/speakers:

get:

description: Returns all speakers

responses:

'200':

description: A list of speakers.

content:

application/json:

schema:

type: array

items:

$ref: '#/components/schemas/Speaker'
Web Application Server
●Server information

○Routing information

■ Request params

■ Response schema
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
Django & OAS
Django Server
●Server information → 

○Routing information → urls.urlpatterns

■ Request params → View, Model

■ Response schema → View, Model
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
Django & OAS
Server Information
● ,


Routing Information
●urlpatterns
# urls.py

openapi_schema_view = get_schema_view(

openapi.Info(

title='Demo API',

default_version='v1',

),

url='https://demo.example.com:3000',

public=True,

)

urlpatterns = [

path('admin/', admin.site.urls),

path('docs/', openapi_schema_view.with_ui(...),

path('', include(router.urls)),

]
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
Django & OAS
Request Params, Response Schema
●Function Based View
○ view request, response 

■ docstring ?

→ API
def speakers_list(request):

"""



response

- type: list

- content

- name: , string

- email: , string

- organization: , object

- name: , string

"""

...

return speakers
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
django/views/generics/edit.py
Django & OAS
Request Params, Response Schema
●Class Based View
○django/views/generics

○cls.model model 

→ response schema

○cls.get_form_class() form 

→ request parameters
CreateView
ModelFormMixin
get_form_class()
SingleObjectMixin
model
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
Flask & OAS
Flask Server
●Server information → 

○Routing information → Flask.view_functions

■ Request params → View?, Model?

■ Response schema → View?, Model?
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
Flask & OAS
Routing Information
●Flask.view_functions
# flask/app.py: Flask

def route(self, rule, **options):

def decorator(f):

endpoint = options.pop('endpoint', None)

self.add_url_rule(rule, endpoint, f, **options)

return f

return decorator

def add_url_rule(self, rule, endpoint, view_func, ...):

…

self.view_functions[endpoint] = view_func

…
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
Flask & OAS
Request Params, Response Schema
●Function View (Django )
○ view request, response 

■ docstring ? → API 

●Pluggable View(Class Based View)
○Function View Extension
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
●Server information
○ 

●Routing information
○ framework routing 

●Request params
○(Django) View class form 

●Response schema
○(Django) View class model
REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
Django REST API
●APIView (Django view wrapping)

●ModelViewSet (generic views)

○Serializer

○Filterset

○Permission

●OpenAPI schema ( )
Django REST Framework
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
●APIView (Django view wrapping)

●ModelViewSet (generic views)

○Serializer
○Filterset

○Permission

●OpenAPI schema ( )
Django REST Framework
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
>>> speaker

<Speaker: Speaker object (1)>

>>> serializer = SpeakerSerializer(speaker)

>>> serializer.data

{'email': 'test@pycon.kr',

'name': 'test',

'created': '2019-08-18T12:15:10.375877'}
●APIView (Django view wrapping)

●ModelViewSet (generic views)

○Serializer
○Filterset

○Permission

●OpenAPI schema ( )
Django REST Framework
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
>>> data = {'email': 'another@pycon.kr',

'name': 'another test',

'created': '2019-08-18T12:16:10.375877'}

>>> serializer = SpeakerSerializer(data=data)

>>> serializer.is_valid()

True

>>> serializer.validated_data

{'email': 'another@pycon.kr',

'name': 'another test',

'created': datetime.datetime(2019, 08, 18, 12, 16, 10,
375877)}
●APIView (Django view wrapping)

●ModelViewSet (generic views)

○Serializer
○Filterset

○Permission

●OpenAPI schema ( )
Django REST Framework
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
>>> serializer.save()

<Speaker: Speaker object (2)>
●APIView (Django view wrapping)

●ModelViewSet (generic views)

○Serializer
○Filterset

○Permission

●OpenAPI schema ( )
Django REST Framework
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
API 

●Django REST Swagger

○ https://github.com/marcgibbons/django-rest-swagger

●DRF Yet another Swagger generator

○ https://github.com/axnsan12/drf-yasg

○ swagger/redoc UI
Django REST Framework
https://www.django-rest-framework.org/topics/documenting-your-api/

REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
API 

●Django REST Swagger

○ https://github.com/marcgibbons/django-rest-swagger

○ 2019-06-04 Deprecated…

●DRF Yet another Swagger generator

○ https://github.com/axnsan12/drf-yasg

○ swagger/redoc UI 

○
Django REST Framework
https://www.django-rest-framework.org/topics/documenting-your-api/

REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
●View serializer request / response schema 

● override decorator 

●OpenAPI Spec 2.0 schema 

○DRF OpenAPI schema
DRF-YASG
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF native vs DRF-YASG
# Django REST Framework (X)

responses:

'200':

content:

application/json:

schema:

properties:

id:

type: integer

readOnly: true

date:

type: string

format: date

packages:

type: array

items:

type: string
# DRF-YASG (O)

responses:

'200':

schema:

type: object

properties:

count:

type: integer

next:

type: string

format: uri

previous:

type: string

format: uri

results:

type: array

items:

$ref: '#/definitions/Record'
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF native vs DRF-YASG
# Django REST Framework (X)

responses:

'200':

content:

application/json:

schema:

properties:

id:

type: integer

readOnly: true

date:

type: string

format: date

packages:

type: array

items:

type: string
# DRF-YASG (O)

responses:

'200':

schema:

type: object

properties:

count:

type: integer

next:

type: string

format: uri

previous:

type: string

format: uri

results:

type: array

items:

$ref: '#/definitions/Record'
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
urlpatterns

(url → view class mappings)
/speakers → SpeakerViewSet
serializer class = SpeakerSerializer
/organizations → OrganizationViewSet
serializer class = OrganizationSerializer
DRF-YASG
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
urlpatterns
SpeakerViewSet
serializer class
Speaker

(id, name, email,
organization_id)
SpeakerSerializer
model = Speaker

id: int

name: str

email: str

organization_id: int, read-only

organization: 

OrganizationSerializer, write-only
DRF-YASG
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
urlpatterns
SpeakerViewSet
serializer class
SpeakerSerializer
model = Speaker

id: int

name: str

email: str

organization_id: int, read-only

organization: 

OrganizationSerializer, write-only
OrganizationSerializer
model = Organization

id: int

name: str
DRF-YASG
# drf_yasg/views.py

class SchemaView(APIView):

...

def get(self, request, version='', format=None):

...

schema = generator.get_schema(request, self.public)

...

return Response(schema)
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
# drf_yasg/generators.py

class OpenAPISchemaGenerator:

def get_schema(self, request=None, public=False):

...

paths, prefix = self.get_paths(endpoints, ...)

...

return openapi.Swagger(

paths=paths,

...

)
def get_paths(self, endpoints, ...):

...

for url, (..., methods) in sorted(endpoints.items()):

...

for method, view in methods:

...

operation = self.get_operation(url, method, ...)

...

...

def get_operation(self, url, method, ...):

...

operation = view_inspector.get_operation(...)

...
urls.urlpatterns
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
# drf_yasg/generators.py

class OpenAPISchemaGenerator:

def get_schema(self, request=None, public=False):

...

paths, prefix = self.get_paths(endpoints, ...)

...

return openapi.Swagger(

paths=paths,

...

)
def get_paths(self, endpoints, ...):

...

for path, (..., methods) in sorted(endpoints.items()):

...

for method, view in methods:

...

operation = self.get_operation(path, method, ...)

...

...

def get_operation(self, path, method, ...):

...

operation = view_inspector.get_operation(...)

...
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
paths:

/speakers:

get:

description: Returns all speakers

responses:

'200':

description: A list of speakers.

content:

application/json:

schema:

type: array

items:

$ref: '#/components/schemas/Speaker'
urls.urlpatterns
DRF-YASG
# drf_yasg/generators.py

class OpenAPISchemaGenerator:

def get_schema(self, request=None, public=False):

...

paths, prefix = self.get_paths(endpoints, ...)

...

return openapi.Swagger(

paths=paths,

...

)
def get_paths(self, endpoints, ...):

...

for url, (..., methods) in sorted(endpoints.items()):

...

for method, view in methods:

...

operation = self.get_operation(url, method, ...)

...

...

def get_operation(self, url, method, ...):

...

operation = view_inspector.get_operation(...)

...
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
# drf_yasg/generators.py

class OpenAPISchemaGenerator:

def get_schema(self, request=None, public=False):

...

paths, prefix = self.get_paths(endpoints, ...)

...

return openapi.Swagger(

paths=paths,

...

)
def get_paths(self, endpoints, ...):

...

for path, (..., methods) in sorted(endpoints.items()):

...

for method, view in methods:

...

operation = self.get_operation(path, method, ...)

...

...

def get_operation(self, path, method, ...):

...

operation = view_inspector.get_operation(...)

...
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
paths:

/speakers:

get:

description: Returns all speakers

responses:

'200':

description: A list of speakers.

content:

application/json:

schema:

type: array

items:

$ref: '#/components/schemas/Speaker'
DRF-YASG
# drf_yasg/generators.py

class OpenAPISchemaGenerator:

def get_schema(self, request=None, public=False):

...

paths, prefix = self.get_paths(endpoints, ...)

...

return openapi.Swagger(

paths=paths,

...

)
def get_paths(self, endpoints, ...):

...

for path, (..., methods) in sorted(endpoints.items()):

...

for method, view in methods:

...

operation = self.get_operation(path, method, ...)

...

...

def get_operation(self, path, method, ...):

...

operation = view_inspector.get_operation(...)

...
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
# drf_yasg/inspectors/view.py

class SwaggerAutoSchema(ViewInspector):

def get_operation(self, operation_keys=None):

...

parameters = body + query

parameters = filter_none(parameters)

parameters = self.add_manual_parameters(parameters)

...

responses = self.get_responses()



return openapi.Operation(

parameters=parameters,

responses=responses,

...

)

REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
# drf_yasg/inspectors/view.py

class SwaggerAutoSchema(ViewInspector):

def get_operation(self, operation_keys=None):

...

parameters = body + query

parameters = filter_none(parameters)

parameters = self.add_manual_parameters(parameters)

...

responses = self.get_responses()



return openapi.Operation(

parameters=parameters,

responses=responses,

...

)

1. self.view serializer 

2. field inspector field 

○ Nested serializer

○ SerializerMethodField

○ Paginated response

3. openapi Response
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
●urlpatterns endpoints(url → view mapping) 

●endpoints iterate url, method request response 

●request response field inspector 

Nested serializer 

● request response OpenAPI schema
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
# main/urls.py

...

openapi_schema_view = get_schema_view(

openapi.Info(

title='Demo API',

default_version='v1',

),

public=True,

)

urlpatterns = [

path('admin/', admin.site.urls),

path('docs/', openapi_schema_view.with_ui('redoc')),

path('', include(router.urls)),

]
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
# main/models.py

class Speaker(models.Model):

id = AutoField(primary_key=True)

email = EmailField()

name = CharField(max_length=10, blank=True)

organization = ForeignKey(

Organization,

null=True,

on_delete=models.SET_NULL,

related_name='speakers'

)

# main/views.py

class SpeakerViewSet(ModelViewSet):

queryset = Speaker.objects.all()

serializer_class = SpeakerSerializer
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
# main/serializers.py

class OrganizationSerializer(ModelSerializer):

...

class SpeakerSerializer(ModelSerializer):

organization = OrganizationSerializer(read_only=True,

help_text='Read-only ')

organization_id = PrimaryKeyRelatedField(source='organization',

queryset=Organization.objects.all(),

write_only=True,

help_text='Write-only ')

class Meta:

model = Speaker

fields = '__all__'

write_only_fields = ('organization_id',)

read_only_fields = ('organization',)
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
# main/serializers.py

class OrganizationSerializer(ModelSerializer):

...

class SpeakerSerializer(ModelSerializer):

organization = OrganizationSerializer(read_only=True,

help_text='Read-only ')

organization_id = PrimaryKeyRelatedField(source='organization',

queryset=Organization.objects.all(),

write_only=True,

help_text='Write-only ')

class Meta:

model = Speaker

fields = '__all__'

write_only_fields = ('organization_id',)

read_only_fields = ('organization',)
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
$ curl -X POST localhost:8000/speakers 

-d "name=test&email=test@pycon.kr&organization_id=1"

{

"id": 1,

"name": "test",

"email": "test@pycon.kr",

"organization": {

"id": 1,

"name": "test organization"

}

}
DRF-YASG
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG Custom Action
# main/views.py

class SpeakerViewSet(ModelViewSet):

queryset = Speaker.objects.all()

serializer_class = SpeakerSerializer

@action(methods=['get'], detail=False)

def count(self, _):

return Response({'result': Speaker.objects.count()})
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG Custom Action
Response schema 

!
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG Custom Action
# main/views.py

class SpeakerViewSet(ModelViewSet):

queryset = Speaker.objects

serializer_class = SpeakerSerializer

@swagger_auto_schema(

operation_description=' API',

responses={

'200': openapi.Response(

description='',

schema=openapi.Schema(

type='object',

properties={'result': openapi.Schema(type='integer')}

)

)

}

)

@action(methods=['get'], detail=False)

def count(self, _):

return Response({'result': Speaker.objects.count()})
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG Custom Action
# main/views.py

class SpeakerCountSerializer(Serializer):

result = IntegerField()

class SpeakerViewSet(ModelViewSet):

queryset = Speaker.objects

serializer_class = SpeakerSerializer

@swagger_auto_schema(

operation_description=' API',

responses={'200': SpeakerCountSerializer}

)

@action(methods=['get'], detail=False)

def count(self, _):

return Response({'result': Speaker.objects.count()})
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG Custom Action
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
● 

○read_only, write_only 

○serializer 

●Redoc UI request 

●Swagger UI 

●OpenAPI Spec 2.0
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
● 

○read_only, write_only 

○serializer 

●Redoc UI request 

●Swagger UI 

●OpenAPI Spec 2.0
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
DRF-YASG
● 

○read_only, write_only 

○serializer 

●Redoc UI request 

●Swagger UI 

●OpenAPI Spec 2.0
REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
https://swagger.io/blog/news/whats-new-in-openapi-3-0/
Flask REST API
●Resource View get, post 

●arg parser View 

●field model marshal
Flask-RESTful
REST API OpenAPI Specification Python Web Apps & OAS Django Flask
●Flask-RESTful 

○ Flask-RESTful API 

● API 

●Flask-RESTful
Flask-RESTPlus
REST API OpenAPI Specification Python Web Apps & OAS Django Flask
●Flask RESTful Swagger 2.0

○ OpenAPI Spec 1.2 

○ 2.0 

●SQLAlchemy Flask RESTful Swagger (SAFRS)

○ DB model class 

○ Model method docstring
API
REST API OpenAPI Specification Python Web Apps & OAS Django Flask
Flask-RESTPlus
REST API OpenAPI Specification Python Web Apps & OAS Django Flask
●Flask RESTful Swagger 2.0

○ OpenAPI Spec 1.2 

○ 2.0 

●SQLAlchemy Flask RESTful Swagger (SAFRS)

○ DB model class 

○ Model method docstring
Flask-RESTPlus
REST API OpenAPI Specification Python Web Apps & OAS Django Flask
●Flask RESTful Swagger 2.0

○ OpenAPI Spec 1.2 

○ 2.0 

●SQLAlchemy Flask RESTful Swagger (SAFRS)

○ DB model class 

○ Model method docstring 

●Flask-RESTPlus 

Flask-RESTPlus
from flask import Flask

from flask_sqlalchemy import SQLAlchemy

from flask_restplus import Api

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite3'

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

api = Api(app)

REST API OpenAPI Specification Python Web Apps & OAS Django Flask
Flask-RESTPlus
class OrganizationModel(db.Model):

id = db.Column(db.Integer, primary_key=True, autoincrement=True)

name = db.Column(db.String(100), nullable=False)

class SpeakerModel(db.Model):

id = db.Column(db.Integer, primary_key=True, autoincrement=True)

name = db.Column(db.String(10), nullable=True)

email = db.Column(db.String(120), unique=True, nullable=False)

organization_id = db.Column(db.Integer, db.ForeignKey('organization_model.id'))

organization = relationship('OrganizationModel')
REST API OpenAPI Specification Python Web Apps & OAS Django Flask
Flask-RESTPlus
organization_output = api.model('OrganizationOutput', {

'name': fields.String

})

speaker_output = api.model('SpeakerOutput', {

'name': fields.String,

'email': fields.String,

'organization': fields.Nested(organization_output)

})

speaker_input = reqparse.RequestParser()

speaker_input.add_argument('email', type=str)

speaker_input.add_argument('name', type=str)

speaker_input.add_argument('organization_id', type=int)

REST API OpenAPI Specification Python Web Apps & OAS Django Flask
Flask-RESTPlus
@api.route('/speakers')

class Speaker(Resource):

@api.marshal_list_with(speaker_output)

def get(self):

return Speaker.query.all()

@api.expect(speaker_input)

@api.marshal_with(speaker_output)

def post(self):

args = speaker_input.parse_args()

speaker = SpeakerModel(**args)

db.session.add(speaker)

db.session.commit()

return speaker
$ curl -X POST localhost:5000/speakers 

-d "name=test&email=test@pycon.kr&organization_id=1"

{

"name": "test",

"email": "test@pycon.kr",

"organization": {

"name": "test organization"

}

}
REST API OpenAPI Specification Python Web Apps & OAS Django Flask
Flask-RESTPlus
REST API OpenAPI Specification Python Web Apps & OAS Django Flask
PyCon Korea 2019 REST API Document Generation
●Web framework → OpenAPI YAML / JSON → Swagger / Redoc UI

● web framework(Bottle, Sanic, Vibora ) 

runtime routing (path → view function) 

○ OpenAPI schema 

○ Sanic-RESTPlus

●drf-yasg, Flask-RESTPlus
www.aitrics.com
contact@aitrics.com
Yongseon Lee <yongseon@aitrics.com>
● REST API (Yongseon Lee) 

18th (Sun) 11:55 ~ 12:35
● Advanced Python testing techniques (Jaeman An)

18th (Sun) 11:55 ~ 12:35
● Django Query Optimization (Soyoung Yoon)

18th (Sun) 13:55 ~ 14:35
● Pickle & Custom Binary Serializer (Young Seok Kim)

18th (Sun) 14:55 ~ 15:35
Talks from AITRICS

More Related Content

PDF
AWS Fargate와 Amazon ECS를 활용한 CI/CD 모범사례 - 유재석, AWS 솔루션즈 아키텍트 :: AWS Game Mast...
PPTX
REST API 설계
PPTX
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
PDF
Jenkins를 활용한 Openshift CI/CD 구성
PPTX
What Is Ansible? | How Ansible Works? | Ansible Tutorial For Beginners | DevO...
PDF
11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례
PPTX
JavaScript Event Loop
PDF
NodeJS for Beginner
AWS Fargate와 Amazon ECS를 활용한 CI/CD 모범사례 - 유재석, AWS 솔루션즈 아키텍트 :: AWS Game Mast...
REST API 설계
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
Jenkins를 활용한 Openshift CI/CD 구성
What Is Ansible? | How Ansible Works? | Ansible Tutorial For Beginners | DevO...
11st Legacy Application의 Spring Cloud 기반 MicroServices로 전환 개발 사례
JavaScript Event Loop
NodeJS for Beginner

What's hot (20)

PPTX
ドメイン駆動設計とマイクロサービス
PPTX
REST-API introduction for developers
PDF
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
PDF
AWS_reInforce_2022_reCap_Ja.pdf
PDF
AWS Black Belt Online Seminar AWS Amplify
PDF
Essentials of container
PPTX
Angular
PPTX
Java Spring framework, Dependency Injection, DI, IoC, Inversion of Control
PDF
API Management
PPTX
Automated Deployments with Ansible
PDF
복잡한 권한신청문제 ConsoleMe로 해결하기 - 손건 (AB180) :: AWS Community Day Online 2021
PPTX
JasperReport
PPTX
Redis
PDF
게임사를 위한 Amazon GameLift 세션 - 이정훈, AWS 솔루션즈 아키텍트
PDF
Terraform -- Infrastructure as Code
PPTX
Design Beautiful REST + JSON APIs
PDF
Introduction to Spring Cloud
PDF
Concevoir, développer et sécuriser des micro-services avec Spring Boot
PDF
AWS Black Belt Online Seminar AWS上のJenkins活用方法
PDF
마이크로서비스를 위한 AWS 아키텍처 패턴 및 모범 사례 - AWS Summit Seoul 2017
ドメイン駆動設計とマイクロサービス
REST-API introduction for developers
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
AWS_reInforce_2022_reCap_Ja.pdf
AWS Black Belt Online Seminar AWS Amplify
Essentials of container
Angular
Java Spring framework, Dependency Injection, DI, IoC, Inversion of Control
API Management
Automated Deployments with Ansible
복잡한 권한신청문제 ConsoleMe로 해결하기 - 손건 (AB180) :: AWS Community Day Online 2021
JasperReport
Redis
게임사를 위한 Amazon GameLift 세션 - 이정훈, AWS 솔루션즈 아키텍트
Terraform -- Infrastructure as Code
Design Beautiful REST + JSON APIs
Introduction to Spring Cloud
Concevoir, développer et sécuriser des micro-services avec Spring Boot
AWS Black Belt Online Seminar AWS上のJenkins活用方法
마이크로서비스를 위한 AWS 아키텍처 패턴 및 모범 사례 - AWS Summit Seoul 2017
Ad

Similar to PyCon Korea 2019 REST API Document Generation (20)

PPTX
Gohan
PDF
Schema-First API Design
PDF
Dead Simple APIs with OpenAPI
PDF
Zen and the Art of REST API documentation - MuCon London 2015
PDF
Crafting APIs
PDF
Building Beautiful REST APIs with ASP.NET Core
PDF
Extensible web #html5j
PDF
PHP. Trends, implementations, frameworks and solutions
PDF
Kubernetes API code-base tour
PDF
Using the new WordPress REST API
PPTX
REST API Best Practices & Implementing in Codeigniter
PDF
Talking to Web Services
PDF
Java-Jersey 到 Python-Flask 服務不中斷重構之旅
PDF
Introduction to CloudStack API
PPTX
API Workshop: Deep dive into REST APIs
PDF
apidays LIVE Helsinki - Implementing OpenAPI and GraphQL Services with gRPC b...
ODP
SPARQLing Services
PPTX
Rest api-basic
PDF
Web Services and Android - OSSPAC 2009
PDF
Services web RESTful
Gohan
Schema-First API Design
Dead Simple APIs with OpenAPI
Zen and the Art of REST API documentation - MuCon London 2015
Crafting APIs
Building Beautiful REST APIs with ASP.NET Core
Extensible web #html5j
PHP. Trends, implementations, frameworks and solutions
Kubernetes API code-base tour
Using the new WordPress REST API
REST API Best Practices & Implementing in Codeigniter
Talking to Web Services
Java-Jersey 到 Python-Flask 服務不中斷重構之旅
Introduction to CloudStack API
API Workshop: Deep dive into REST APIs
apidays LIVE Helsinki - Implementing OpenAPI and GraphQL Services with gRPC b...
SPARQLing Services
Rest api-basic
Web Services and Android - OSSPAC 2009
Services web RESTful
Ad

Recently uploaded (20)

PDF
PPT on Performance Review to get promotions
PDF
Mitigating Risks through Effective Management for Enhancing Organizational Pe...
PDF
Operating System & Kernel Study Guide-1 - converted.pdf
PPTX
Artificial Intelligence
PPTX
bas. eng. economics group 4 presentation 1.pptx
PDF
Enhancing Cyber Defense Against Zero-Day Attacks using Ensemble Neural Networks
PPTX
OOP with Java - Java Introduction (Basics)
PPTX
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
PPTX
additive manufacturing of ss316l using mig welding
PDF
BIO-INSPIRED HORMONAL MODULATION AND ADAPTIVE ORCHESTRATION IN S-AI-GPT
PDF
Embodied AI: Ushering in the Next Era of Intelligent Systems
PPTX
Geodesy 1.pptx...............................................
PPTX
Engineering Ethics, Safety and Environment [Autosaved] (1).pptx
DOCX
ASol_English-Language-Literature-Set-1-27-02-2023-converted.docx
PDF
737-MAX_SRG.pdf student reference guides
PDF
Automation-in-Manufacturing-Chapter-Introduction.pdf
PPTX
CYBER-CRIMES AND SECURITY A guide to understanding
PDF
keyrequirementskkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
PDF
Model Code of Practice - Construction Work - 21102022 .pdf
PPTX
Safety Seminar civil to be ensured for safe working.
PPT on Performance Review to get promotions
Mitigating Risks through Effective Management for Enhancing Organizational Pe...
Operating System & Kernel Study Guide-1 - converted.pdf
Artificial Intelligence
bas. eng. economics group 4 presentation 1.pptx
Enhancing Cyber Defense Against Zero-Day Attacks using Ensemble Neural Networks
OOP with Java - Java Introduction (Basics)
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
additive manufacturing of ss316l using mig welding
BIO-INSPIRED HORMONAL MODULATION AND ADAPTIVE ORCHESTRATION IN S-AI-GPT
Embodied AI: Ushering in the Next Era of Intelligent Systems
Geodesy 1.pptx...............................................
Engineering Ethics, Safety and Environment [Autosaved] (1).pptx
ASol_English-Language-Literature-Set-1-27-02-2023-converted.docx
737-MAX_SRG.pdf student reference guides
Automation-in-Manufacturing-Chapter-Introduction.pdf
CYBER-CRIMES AND SECURITY A guide to understanding
keyrequirementskkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
Model Code of Practice - Construction Work - 21102022 .pdf
Safety Seminar civil to be ensured for safe working.

PyCon Korea 2019 REST API Document Generation

  • 2. 5 Python backend app Flask 2 Django
  • 3. ●REST API ●OpenAPI Specification ●Python Web Applications & OpenAPI Specification ●Django API ●Flask API
  • 5. REST API ? HTTP METHODS https://api.example.com/speakers https://api.example.com/speakers/1 GET 1 POST - PUT request body request body field null 1 request body request body field null PATCH request body request body field 1 request body request body field DELETE 1 OpenAPI Specification Python Web Apps & OAS Django FlaskREST API Representational State Transfer
  • 6. ( API ) REST API OpenAPI Specification Python Web Apps & OAS Django FlaskREST API
  • 7. ●API , ●Host, port ● ●URI ●URI HTTP method ● request header, body ● response status code, body REST API OpenAPI Specification Python Web Apps & OAS Django FlaskREST API
  • 8. REST API OpenAPI Specification Python Web Apps & OAS Django FlaskREST API
  • 9. ..
 ● .. ● ● REST API OpenAPI Specification Python Web Apps & OAS Django FlaskREST API
  • 11. RESTful API JSON, YAML API , / 
 Swagger OpenAPI Initiative OpenAPI Specification https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
  • 12. API toolset ●Swagger Codegen ●Swagger Editor ●Swagger UI Swagger UI ●OpenAPI JSON/YAML 
 API Swagger? https://petstore.swagger.io/ REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
  • 13. API toolset ●Swagger Codegen ●Swagger Editor ●Swagger UI Swagger UI ●OpenAPI JSON/YAML 
 API Swagger? https://petstore.swagger.io/ REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
  • 14. API toolset ●Swagger Codegen ●Swagger Editor ●Swagger UI Swagger UI ●OpenAPI JSON/YAML 
 API Swagger? https://petstore.swagger.io/ REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
  • 15. API toolset ●Swagger Codegen ●Swagger Editor ●Swagger UI Swagger UI ●OpenAPI JSON/YAML 
 API Swagger? https://petstore.swagger.io/ REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
  • 16. API toolset ●Swagger Codegen ●Swagger Editor ●Swagger UI Swagger UI ●OpenAPI JSON/YAML 
 API Swagger? REST API Python Web Apps & OAS Django FlaskOpenAPI Specification https://petstore.swagger.io/
  • 17. title: Sample PyCON speaker API description: This is a sample server for a PyCON speaker management. termsOfService: http://example.com/terms/ contact: name: API Support url: http://www.example.com/support email: support@example.com license: name: MIT version: 1.0.1 OpenAPI Specification YAML https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
  • 18. servers: - url: https://pycon-speaker.com:{port}/{basePath} description: The production API server variables: port: enum: - '443' - '8443' default: '8443' description: 8443 is for demo. basePath: default: v2 OpenAPI Specification YAML https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
  • 19. paths: /speakers: get: description: Returns all speakers from the system that the user has access to responses: '200': description: A list of speakers. content: application/json: schema: type: array items: $ref: '#/components/schemas/Speaker' OpenAPI Specification YAML https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
  • 20. components: schemas: Speaker: required: - id - email properties: id: type: integer format: int64 email: type: string name: type: string OpenAPI Specification YAML https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md REST API Python Web Apps & OAS Django FlaskOpenAPI Specification
  • 21. OpenAPI Specification YAML https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md REST API Python Web Apps & OAS Django FlaskOpenAPI Specification OpenAPI Specification
 JSON / YAML APISwagger UI paths: /speakers: get: description: Returns all speakers from the system that the user has access to responses: '200': description: A list of speakers. content: application/json: schema: type: array items: $ref: '#/components/schemas/Speaker'
  • 22. Python Web Application & 
 OpenAPI Specification
  • 23. Generating OpenAPI YAML Web Application Server ●Server information ○Base URL, port, ... ●Routing information ○ path ●Request params ●Response schema REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 24. Generating OpenAPI YAML servers: - url: https://pycon-speaker.com:{port}/{basePath} description: The production API server variables: port: enum: - '443' - '8443' default: '8443' description: 8443 is for demo. basePath: default: v2 Web Application Server ●Server information ○Routing information ■ Request params ■ Response schema REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 25. Generating OpenAPI YAML paths: /speakers: get: description: Returns all speakers responses: '200': description: A list of speakers. content: application/json: schema: type: array items: $ref: '#/components/schemas/Speaker' Web Application Server ●Server information ○Routing information ■ Request params ■ Response schema REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 26. Generating OpenAPI YAML paths: /speakers: get: description: Returns all speakers responses: '200': description: A list of speakers. content: application/json: schema: type: array items: $ref: '#/components/schemas/Speaker' Web Application Server ●Server information ○Routing information ■ Request params ■ Response schema REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 27. Generating OpenAPI YAML paths: /speakers: get: description: Returns all speakers responses: '200': description: A list of speakers. content: application/json: schema: type: array items: $ref: '#/components/schemas/Speaker' Web Application Server ●Server information ○Routing information ■ Request params ■ Response schema REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 28. Django & OAS Django Server ●Server information → ○Routing information → urls.urlpatterns ■ Request params → View, Model ■ Response schema → View, Model REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 29. Django & OAS Server Information ● , Routing Information ●urlpatterns # urls.py openapi_schema_view = get_schema_view( openapi.Info( title='Demo API', default_version='v1', ), url='https://demo.example.com:3000', public=True, ) urlpatterns = [ path('admin/', admin.site.urls), path('docs/', openapi_schema_view.with_ui(...), path('', include(router.urls)), ] REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 30. Django & OAS Request Params, Response Schema ●Function Based View ○ view request, response ■ docstring ?
 → API def speakers_list(request): """ response - type: list - content - name: , string - email: , string - organization: , object - name: , string """ ... return speakers REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 31. django/views/generics/edit.py Django & OAS Request Params, Response Schema ●Class Based View ○django/views/generics ○cls.model model 
 → response schema ○cls.get_form_class() form 
 → request parameters CreateView ModelFormMixin get_form_class() SingleObjectMixin model REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 32. Flask & OAS Flask Server ●Server information → ○Routing information → Flask.view_functions ■ Request params → View?, Model? ■ Response schema → View?, Model? REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 33. Flask & OAS Routing Information ●Flask.view_functions # flask/app.py: Flask def route(self, rule, **options): def decorator(f): endpoint = options.pop('endpoint', None) self.add_url_rule(rule, endpoint, f, **options) return f return decorator def add_url_rule(self, rule, endpoint, view_func, ...): … self.view_functions[endpoint] = view_func … REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 34. Flask & OAS Request Params, Response Schema ●Function View (Django ) ○ view request, response ■ docstring ? → API ●Pluggable View(Class Based View) ○Function View Extension REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 35. ●Server information ○ ●Routing information ○ framework routing ●Request params ○(Django) View class form ●Response schema ○(Django) View class model REST API OpenAPI Specification Django FlaskPython Web Apps & OAS
  • 37. ●APIView (Django view wrapping) ●ModelViewSet (generic views) ○Serializer ○Filterset ○Permission ●OpenAPI schema ( ) Django REST Framework REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 38. ●APIView (Django view wrapping) ●ModelViewSet (generic views) ○Serializer ○Filterset ○Permission ●OpenAPI schema ( ) Django REST Framework REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango >>> speaker <Speaker: Speaker object (1)> >>> serializer = SpeakerSerializer(speaker) >>> serializer.data {'email': 'test@pycon.kr', 'name': 'test', 'created': '2019-08-18T12:15:10.375877'}
  • 39. ●APIView (Django view wrapping) ●ModelViewSet (generic views) ○Serializer ○Filterset ○Permission ●OpenAPI schema ( ) Django REST Framework REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango >>> data = {'email': 'another@pycon.kr', 'name': 'another test', 'created': '2019-08-18T12:16:10.375877'} >>> serializer = SpeakerSerializer(data=data) >>> serializer.is_valid() True >>> serializer.validated_data {'email': 'another@pycon.kr', 'name': 'another test', 'created': datetime.datetime(2019, 08, 18, 12, 16, 10, 375877)}
  • 40. ●APIView (Django view wrapping) ●ModelViewSet (generic views) ○Serializer ○Filterset ○Permission ●OpenAPI schema ( ) Django REST Framework REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango >>> serializer.save() <Speaker: Speaker object (2)>
  • 41. ●APIView (Django view wrapping) ●ModelViewSet (generic views) ○Serializer ○Filterset ○Permission ●OpenAPI schema ( ) Django REST Framework REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 42. API ●Django REST Swagger ○ https://github.com/marcgibbons/django-rest-swagger
 ●DRF Yet another Swagger generator ○ https://github.com/axnsan12/drf-yasg ○ swagger/redoc UI Django REST Framework https://www.django-rest-framework.org/topics/documenting-your-api/ REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 43. API ●Django REST Swagger ○ https://github.com/marcgibbons/django-rest-swagger ○ 2019-06-04 Deprecated…
 ●DRF Yet another Swagger generator ○ https://github.com/axnsan12/drf-yasg ○ swagger/redoc UI ○ Django REST Framework https://www.django-rest-framework.org/topics/documenting-your-api/ REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 44. ●View serializer request / response schema ● override decorator ●OpenAPI Spec 2.0 schema ○DRF OpenAPI schema DRF-YASG REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 45. DRF native vs DRF-YASG # Django REST Framework (X) responses: '200': content: application/json: schema: properties: id: type: integer readOnly: true date: type: string format: date packages: type: array items: type: string # DRF-YASG (O) responses: '200': schema: type: object properties: count: type: integer next: type: string format: uri previous: type: string format: uri results: type: array items: $ref: '#/definitions/Record' REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 46. DRF native vs DRF-YASG # Django REST Framework (X) responses: '200': content: application/json: schema: properties: id: type: integer readOnly: true date: type: string format: date packages: type: array items: type: string # DRF-YASG (O) responses: '200': schema: type: object properties: count: type: integer next: type: string format: uri previous: type: string format: uri results: type: array items: $ref: '#/definitions/Record' REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 47. DRF-YASG REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango urlpatterns (url → view class mappings) /speakers → SpeakerViewSet serializer class = SpeakerSerializer /organizations → OrganizationViewSet serializer class = OrganizationSerializer
  • 48. DRF-YASG REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango urlpatterns SpeakerViewSet serializer class Speaker (id, name, email, organization_id) SpeakerSerializer model = Speaker id: int name: str email: str organization_id: int, read-only organization: OrganizationSerializer, write-only
  • 49. DRF-YASG REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango urlpatterns SpeakerViewSet serializer class SpeakerSerializer model = Speaker id: int name: str email: str organization_id: int, read-only organization: OrganizationSerializer, write-only OrganizationSerializer model = Organization id: int name: str
  • 50. DRF-YASG # drf_yasg/views.py class SchemaView(APIView): ... def get(self, request, version='', format=None): ... schema = generator.get_schema(request, self.public) ... return Response(schema) REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 51. DRF-YASG # drf_yasg/generators.py class OpenAPISchemaGenerator: def get_schema(self, request=None, public=False): ... paths, prefix = self.get_paths(endpoints, ...) ... return openapi.Swagger( paths=paths, ... ) def get_paths(self, endpoints, ...): ... for url, (..., methods) in sorted(endpoints.items()): ... for method, view in methods: ... operation = self.get_operation(url, method, ...) ... ... def get_operation(self, url, method, ...): ... operation = view_inspector.get_operation(...) ... urls.urlpatterns REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 52. DRF-YASG # drf_yasg/generators.py class OpenAPISchemaGenerator: def get_schema(self, request=None, public=False): ... paths, prefix = self.get_paths(endpoints, ...) ... return openapi.Swagger( paths=paths, ... ) def get_paths(self, endpoints, ...): ... for path, (..., methods) in sorted(endpoints.items()): ... for method, view in methods: ... operation = self.get_operation(path, method, ...) ... ... def get_operation(self, path, method, ...): ... operation = view_inspector.get_operation(...) ... REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango paths: /speakers: get: description: Returns all speakers responses: '200': description: A list of speakers. content: application/json: schema: type: array items: $ref: '#/components/schemas/Speaker' urls.urlpatterns
  • 53. DRF-YASG # drf_yasg/generators.py class OpenAPISchemaGenerator: def get_schema(self, request=None, public=False): ... paths, prefix = self.get_paths(endpoints, ...) ... return openapi.Swagger( paths=paths, ... ) def get_paths(self, endpoints, ...): ... for url, (..., methods) in sorted(endpoints.items()): ... for method, view in methods: ... operation = self.get_operation(url, method, ...) ... ... def get_operation(self, url, method, ...): ... operation = view_inspector.get_operation(...) ... REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 54. DRF-YASG # drf_yasg/generators.py class OpenAPISchemaGenerator: def get_schema(self, request=None, public=False): ... paths, prefix = self.get_paths(endpoints, ...) ... return openapi.Swagger( paths=paths, ... ) def get_paths(self, endpoints, ...): ... for path, (..., methods) in sorted(endpoints.items()): ... for method, view in methods: ... operation = self.get_operation(path, method, ...) ... ... def get_operation(self, path, method, ...): ... operation = view_inspector.get_operation(...) ... REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango paths: /speakers: get: description: Returns all speakers responses: '200': description: A list of speakers. content: application/json: schema: type: array items: $ref: '#/components/schemas/Speaker'
  • 55. DRF-YASG # drf_yasg/generators.py class OpenAPISchemaGenerator: def get_schema(self, request=None, public=False): ... paths, prefix = self.get_paths(endpoints, ...) ... return openapi.Swagger( paths=paths, ... ) def get_paths(self, endpoints, ...): ... for path, (..., methods) in sorted(endpoints.items()): ... for method, view in methods: ... operation = self.get_operation(path, method, ...) ... ... def get_operation(self, path, method, ...): ... operation = view_inspector.get_operation(...) ... REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 56. DRF-YASG # drf_yasg/inspectors/view.py class SwaggerAutoSchema(ViewInspector): def get_operation(self, operation_keys=None): ... parameters = body + query parameters = filter_none(parameters) parameters = self.add_manual_parameters(parameters) ... responses = self.get_responses() return openapi.Operation( parameters=parameters, responses=responses, ... ) REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 57. DRF-YASG # drf_yasg/inspectors/view.py class SwaggerAutoSchema(ViewInspector): def get_operation(self, operation_keys=None): ... parameters = body + query parameters = filter_none(parameters) parameters = self.add_manual_parameters(parameters) ... responses = self.get_responses() return openapi.Operation( parameters=parameters, responses=responses, ... ) 1. self.view serializer 2. field inspector field ○ Nested serializer ○ SerializerMethodField ○ Paginated response 3. openapi Response REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 58. DRF-YASG ●urlpatterns endpoints(url → view mapping) 
 ●endpoints iterate url, method request response 
 ●request response field inspector 
 Nested serializer 
 ● request response OpenAPI schema REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 59. DRF-YASG # main/urls.py ... openapi_schema_view = get_schema_view( openapi.Info( title='Demo API', default_version='v1', ), public=True, ) urlpatterns = [ path('admin/', admin.site.urls), path('docs/', openapi_schema_view.with_ui('redoc')), path('', include(router.urls)), ] REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 60. DRF-YASG # main/models.py class Speaker(models.Model): id = AutoField(primary_key=True) email = EmailField() name = CharField(max_length=10, blank=True) organization = ForeignKey( Organization, null=True, on_delete=models.SET_NULL, related_name='speakers' ) # main/views.py class SpeakerViewSet(ModelViewSet): queryset = Speaker.objects.all() serializer_class = SpeakerSerializer REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 61. DRF-YASG # main/serializers.py class OrganizationSerializer(ModelSerializer): ... class SpeakerSerializer(ModelSerializer): organization = OrganizationSerializer(read_only=True, help_text='Read-only ') organization_id = PrimaryKeyRelatedField(source='organization', queryset=Organization.objects.all(), write_only=True, help_text='Write-only ') class Meta: model = Speaker fields = '__all__' write_only_fields = ('organization_id',) read_only_fields = ('organization',) REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 62. DRF-YASG # main/serializers.py class OrganizationSerializer(ModelSerializer): ... class SpeakerSerializer(ModelSerializer): organization = OrganizationSerializer(read_only=True, help_text='Read-only ') organization_id = PrimaryKeyRelatedField(source='organization', queryset=Organization.objects.all(), write_only=True, help_text='Write-only ') class Meta: model = Speaker fields = '__all__' write_only_fields = ('organization_id',) read_only_fields = ('organization',) REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango $ curl -X POST localhost:8000/speakers -d "name=test&email=test@pycon.kr&organization_id=1" { "id": 1, "name": "test", "email": "test@pycon.kr", "organization": { "id": 1, "name": "test organization" } }
  • 63. DRF-YASG REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 64. DRF-YASG REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 65. DRF-YASG Custom Action # main/views.py class SpeakerViewSet(ModelViewSet): queryset = Speaker.objects.all() serializer_class = SpeakerSerializer @action(methods=['get'], detail=False) def count(self, _): return Response({'result': Speaker.objects.count()}) REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 66. DRF-YASG Custom Action Response schema 
 ! REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 67. DRF-YASG Custom Action # main/views.py class SpeakerViewSet(ModelViewSet): queryset = Speaker.objects serializer_class = SpeakerSerializer @swagger_auto_schema( operation_description=' API', responses={ '200': openapi.Response( description='', schema=openapi.Schema( type='object', properties={'result': openapi.Schema(type='integer')} ) ) } ) @action(methods=['get'], detail=False) def count(self, _): return Response({'result': Speaker.objects.count()}) REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 68. DRF-YASG Custom Action # main/views.py class SpeakerCountSerializer(Serializer): result = IntegerField() class SpeakerViewSet(ModelViewSet): queryset = Speaker.objects serializer_class = SpeakerSerializer @swagger_auto_schema( operation_description=' API', responses={'200': SpeakerCountSerializer} ) @action(methods=['get'], detail=False) def count(self, _): return Response({'result': Speaker.objects.count()}) REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 69. DRF-YASG Custom Action REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 70. DRF-YASG ● ○read_only, write_only ○serializer ●Redoc UI request ●Swagger UI ●OpenAPI Spec 2.0 REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 71. DRF-YASG ● ○read_only, write_only ○serializer ●Redoc UI request ●Swagger UI ●OpenAPI Spec 2.0 REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango
  • 72. DRF-YASG ● ○read_only, write_only ○serializer ●Redoc UI request ●Swagger UI ●OpenAPI Spec 2.0 REST API OpenAPI Specification Python Web Apps & OAS FlaskDjango https://swagger.io/blog/news/whats-new-in-openapi-3-0/
  • 74. ●Resource View get, post 
 ●arg parser View 
 ●field model marshal Flask-RESTful REST API OpenAPI Specification Python Web Apps & OAS Django Flask
  • 75. ●Flask-RESTful ○ Flask-RESTful API ● API ●Flask-RESTful Flask-RESTPlus REST API OpenAPI Specification Python Web Apps & OAS Django Flask
  • 76. ●Flask RESTful Swagger 2.0 ○ OpenAPI Spec 1.2 ○ 2.0 ●SQLAlchemy Flask RESTful Swagger (SAFRS) ○ DB model class ○ Model method docstring API REST API OpenAPI Specification Python Web Apps & OAS Django Flask
  • 77. Flask-RESTPlus REST API OpenAPI Specification Python Web Apps & OAS Django Flask ●Flask RESTful Swagger 2.0 ○ OpenAPI Spec 1.2 ○ 2.0 ●SQLAlchemy Flask RESTful Swagger (SAFRS) ○ DB model class ○ Model method docstring
  • 78. Flask-RESTPlus REST API OpenAPI Specification Python Web Apps & OAS Django Flask ●Flask RESTful Swagger 2.0 ○ OpenAPI Spec 1.2 ○ 2.0 ●SQLAlchemy Flask RESTful Swagger (SAFRS) ○ DB model class ○ Model method docstring 
 ●Flask-RESTPlus 

  • 79. Flask-RESTPlus from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_restplus import Api app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite3' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) api = Api(app) REST API OpenAPI Specification Python Web Apps & OAS Django Flask
  • 80. Flask-RESTPlus class OrganizationModel(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(100), nullable=False) class SpeakerModel(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(10), nullable=True) email = db.Column(db.String(120), unique=True, nullable=False) organization_id = db.Column(db.Integer, db.ForeignKey('organization_model.id')) organization = relationship('OrganizationModel') REST API OpenAPI Specification Python Web Apps & OAS Django Flask
  • 81. Flask-RESTPlus organization_output = api.model('OrganizationOutput', { 'name': fields.String }) speaker_output = api.model('SpeakerOutput', { 'name': fields.String, 'email': fields.String, 'organization': fields.Nested(organization_output) }) speaker_input = reqparse.RequestParser() speaker_input.add_argument('email', type=str) speaker_input.add_argument('name', type=str) speaker_input.add_argument('organization_id', type=int) REST API OpenAPI Specification Python Web Apps & OAS Django Flask
  • 82. Flask-RESTPlus @api.route('/speakers') class Speaker(Resource): @api.marshal_list_with(speaker_output) def get(self): return Speaker.query.all() @api.expect(speaker_input) @api.marshal_with(speaker_output) def post(self): args = speaker_input.parse_args() speaker = SpeakerModel(**args) db.session.add(speaker) db.session.commit() return speaker $ curl -X POST localhost:5000/speakers -d "name=test&email=test@pycon.kr&organization_id=1" { "name": "test", "email": "test@pycon.kr", "organization": { "name": "test organization" } } REST API OpenAPI Specification Python Web Apps & OAS Django Flask
  • 83. Flask-RESTPlus REST API OpenAPI Specification Python Web Apps & OAS Django Flask
  • 85. ●Web framework → OpenAPI YAML / JSON → Swagger / Redoc UI ● web framework(Bottle, Sanic, Vibora ) 
 runtime routing (path → view function) ○ OpenAPI schema ○ Sanic-RESTPlus ●drf-yasg, Flask-RESTPlus
  • 86. www.aitrics.com contact@aitrics.com Yongseon Lee <yongseon@aitrics.com> ● REST API (Yongseon Lee) 
 18th (Sun) 11:55 ~ 12:35 ● Advanced Python testing techniques (Jaeman An)
 18th (Sun) 11:55 ~ 12:35 ● Django Query Optimization (Soyoung Yoon)
 18th (Sun) 13:55 ~ 14:35 ● Pickle & Custom Binary Serializer (Young Seok Kim)
 18th (Sun) 14:55 ~ 15:35 Talks from AITRICS