KEMBAR78
Django REST Framework における API 実装プラクティス | PyCon JP 2018 | PDF
Django REST Framework
API
Masashi SHIBATA
c-bata c_bata_! "
PyCon JP 2018 Day1
go-prompt, kube-prompt


https://codezine.jp/article/corner/749
c-bata c_bata_! "
Topic 1
PageNumberPagination
CursorPagination
LimitOffsetPagination
CLASS
http://example.com/snippets/?page=4
PageNumberPagination
http://example.com/snippets/?limit=5&offset=400
prev: http://example.com/snippets/?cursor=cj0xJnA9MjAxOC
next: http://example.com/snippets/?cursor=povlJDFkfhgf0lAj
LimitOffsetPagination
CursorPagination
http://example.com/snippets/?page=4
PageNumberPagination
http://example.com/snippets/?limit=5&offset=400
prev: http://example.com/snippets/?cursor=cj0xJnA9MjAxOC
next: http://example.com/snippets/?cursor=povlJDFkfhgf0lAj
LimitOffsetPagination
CursorPagination
per_page
http://example.com/snippets/?page=4
PageNumberPagination
http://example.com/snippets/?limit=50&offset=250
prev: http://example.com/snippets/?cursor=cj0xJnA9MjAxOC
next: http://example.com/snippets/?cursor=povlJDFkfhgf0lAj
LimitOffsetPagination
CursorPagination
(offset) (limit)
page
http://example.com/snippets/?page=4
PageNumberPagination
http://example.com/snippets/?limit=50&offset=250
prev: http://example.com/snippets/?cursor=cj0xJnA9MjAxOC
next: http://example.com/snippets/?cursor=povlJDFkfhgf0lAj
LimitOffsetPagination
CursorPagination
ID( )
( )
http://example.com/snippets/?page=4
PageNumberPagination
http://example.com/snippets/?limit=50&offset=250
prev: http://example.com/snippets/?cursor=cj0xJnA9MjAxOC
next: http://example.com/snippets/?cursor=povlJDFkfhgf0lAj
LimitOffsetPagination
CursorPagination
http://example.com/snippets/?page=4
PageNumberPagination
http://example.com/snippets/?limit=50&offset=250
prev: http://example.com/snippets/?cursor=cj0xJnA9MjAxOC
next: http://example.com/snippets/?cursor=povlJDFkfhgf0lAj
LimitOffsetPagination
CursorPagination
(or )
http://example.com/snippets/?page=4
PageNumberPagination
http://example.com/snippets/?limit=50&offset=250
prev: http://example.com/snippets/?cursor=cj0xJnA9MjAxOC
next: http://example.com/snippets/?cursor=povlJDFkfhgf0lAj
LimitOffsetPagination
CursorPagination
※ max_id since_id
examle.com/snippets?since_id=6
http://example.com/snippets/?page=4
PageNumberPagination
http://example.com/snippets/?limit=50&offset=250
prev: http://example.com/snippets/?cursor=cj0xJnA9MjAxOC
next: http://example.com/snippets/?cursor=povlJDFkfhgf0lAj
LimitOffsetPagination
CursorPagination
id or
http://example.com/snippets/?page=4
PageNumberPagination
http://example.com/snippets/?limit=50&offset=250
prev: http://example.com/snippets/?cursor=cj0xJnA9MjAxOC
next: http://example.com/snippets/?cursor=povlJDFkfhgf0lAj
LimitOffsetPagination
CursorPagination
1 74 102 85 113 96 12
1 74 102 85 113 96 12
1 74 102 85 113 96 12
1 74 102 85 113 96 12
1 74 102 85 113 96 12
id = 3
id=6
1 74 102 85 113 96 12
1 74 102 85 113 96 12
1 74 102 85 113 96 121 74 102 85 113 96 12
1 74 102 85 113 96 12
5
1
1 74 102 85 113 96 12
1 74 102 85 113 96 12
1 74 102 85 113 96 12
1 74 102 85 113 96 12
id id id id id id id id
3
id id id id id id id id id id id id id id id id
id id id id id id id id id id id id id id id id
id id id id id id id id id id id id id id id id
id id id id id id id id id id id id id id id id


=
SELECT id FROM snippets
WHERE is_public = 1
AND created_at > '2018-09-15 08:28:53.312612’
ORDER BY created_at ASC LIMIT 101;
ALTER TABLE snippets
ADD INDEX ix_created_public(created_at, is_public);
SQL
Index
INDEX
D, J, Z
INDEX
A, B, D
+
A 1
INDEX
F, H, J B 8
INDEX
L, P, Z D 20
INDEX
20, 60, 80
INDEX
1, 8, 20
+
1 c-bata 24
INDEX
21, 50, 60
+
8 denari 23
INDEX
65, 76, 80
+
20 cstoku 25
(InnoDB)
INDEX
D, J, Z
INDEX
A, B, D
+
A 1
INDEX
F, H, J B 8
INDEX
L, P, Z D 20
INDEX
20, 60, 80
INDEX
1, 8, 20
+
1 c-bata 24
INDEX
21, 50, 60
+
8 denari 23
INDEX
65, 76, 80
+
20 cstoku 25
(InnoDB)
INDEX
D, J, Z
INDEX
A, B, D
+
A 1
INDEX
F, H, J B 8
INDEX
L, P, Z D 20
INDEX
20, 60, 80
INDEX
1, 8, 20
+
1 c-bata 24
INDEX
21, 50, 60
+
8 denari 23
INDEX
65, 76, 80
+
20 cstoku 25
(InnoDB)
INDEX
INDEX
D, J, Z
INDEX
A, B, D
+
A 1
INDEX
F, H, J B 8
INDEX
L, P, Z D 20
INDEX
20, 60, 80
INDEX
1, 8, 20
+
1 c-bata 24
INDEX
21, 50, 60
+
8 denari 23
INDEX
65, 76, 80
+
20 cstoku 25
(InnoDB)
INDEX
D, J, Z
INDEX
A, B, D
+
A 1
INDEX
F, H, J B 8
INDEX
L, P, Z D 20
INDEX
20, 60, 80
INDEX
1, 8, 20
+
1 c-bata 24
INDEX
21, 50, 60
+
8 denari 23
INDEX
65, 76, 80
+
20 cstoku 25
(InnoDB)
OFFSET
INDEX
D, J, Z
INDEX
A, B, D
+
A 1
INDEX
F, H, J B 8
INDEX
L, P, Z D 20
INDEX
20, 60, 80
INDEX
1, 8, 20
+
1 c-bata 24
INDEX
21, 50, 60
+
8 denari 23
INDEX
65, 76, 80
+
20 cstoku 25
(InnoDB)
SELECT id FROM snippets
WHERE is_public = 1
AND created_at > '2018-09-15 08:28:53.312612’
ORDER BY created_at ASC LIMIT 101;
ALTER TABLE snippets
ADD INDEX ix_created_public(created_at, is_public);
SQL
Index
SELECT id FROM snippets
WHERE is_public = 1
AND created_at > '2018-09-15 08:28:53.312612’
ORDER BY created_at ASC LIMIT 101;
ALTER TABLE snippets
ADD INDEX ix_created_public(created_at, is_public);
SQL
Index
id, is_public, created_at
SELECT id FROM snippets
WHERE is_public = 1
AND created_at > '2018-09-15 08:28:53.312612’
ORDER BY created_at ASC LIMIT 101;
ALTER TABLE snippets
ADD INDEX ix_created_public(created_at, is_public);
SQL
Index
id, is_public, created_at
SELECT id FROM snippets
WHERE is_public = 1
AND created_at > '2018-09-15 08:28:53.312612’
ORDER BY created_at ASC LIMIT 101;
ALTER TABLE snippets
ADD INDEX ix_created_public(created_at, is_public);
SQL
Index
id, is_public, created_at
created_at is_public
Topic 2
AnonRateThrottle
ScopedRateThrottle
UserRateThrottle
KEYWORDS
•
• CDN (akamai, fastly, cloudflare, …)
• (Nginx, apache, …)
• Django
• AnonRateThrottle
• UserRateThrottle
• ScopedRateThrottle
• CDN Rate Limiting, DDoS Protection
• https://docs.fastly.com/api/
• https://developer.akamai.com/blog/2018/05/30/
demystifying-api-rate-limiting
•
• https://www.nginx.com/blog/rate-limiting-nginx/
• AnonRateThrottle:
• IP (X-Forwarded-For WSGI environ
REMOTE_ADDR )
• UserRateThrottle:
•
• ScopedRateThrottle:
•
• AnonRateThrottle:
• IP (X-Forwarded-For WSGI environ
REMOTE_ADDR )
• UserRateThrottle:
•
• ScopedRateThrottle:
•
CDN Nginx
• AnonRateThrottle:
• IP (X-Forwarded-For WSGI environ
REMOTE_ADDR )
• UserRateThrottle:
•
• ScopedRateThrottle:
•
Github
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
‘rest_framework.throttling.AnonRateThrottle',
‘rest_framework.throttling.UserRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'anon': ‘10/min',
'user': ‘100/min'
}
}
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
‘rest_framework.throttling.AnonRateThrottle',
‘rest_framework.throttling.UserRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'anon': ‘10/min',
'user': ‘100/min'
}
}
sec, min, hour, day
1
s m, h, d
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
‘rest_framework.throttling.AnonRateThrottle',
‘rest_framework.throttling.UserRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'anon': ‘10/min',
'user': ‘100/min'
}
}
Django
LocalMemCache
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
‘rest_framework.throttling.AnonRateThrottle',
‘rest_framework.throttling.UserRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'anon': ‘10/min',
'user': ‘100/min'
}
}
Github
RateThrottle
https://github.com/c-bata/django-api-practices
•
• clients/dos.py : 10
• clients/throttle_client.py :
•
• RATE_LIMIT=true
• anon: 3req/s , user: 10req/s
•
• clients/dos.py : 10
• clients/throttle_client.py :
•
• RATE_LIMIT=true
• anon: 3req/s , user: 10req/s
https://github.com/c-bata/django-api-practices
TokenBucketAlgorithm
Python 2
14
• CDN Nginx
• REST Framework 3
• UserRateLimit
• Rate Limit 

Topic 3
TokenAuthentication JWT
TokenAuthentication
djangorestframework-jwt
CLASS
• TokenAuthentication:
• djangorestframework-jwt: JSON Web Token
• https://github.com/GetBlimp/django-rest-framework-jwt
• Refresh
JWT
JWT
JSON Web Token
Claim JSON 

( RFC7519)
https://jwt.io
https://jwt.io
{header}.{payload}.{signature}
header claims urlsafe base64 encode
https://jwt.io
( JWT)
https://jwt.io
payload urlsafe base64 decode
RS HS
• HMAC: ) HS256
•
•
•
• : ) RS256. PS ES
•
•
RS HS
• HMAC: ) HS256
•
•
•
• : ) RS256
•
•


HMAC
RS HS
• HMAC: ) HS256
•
•
•
• : ) RS256
•
•
djangorestframework-jwt 

HS256
RS HS
• HMAC: ) HS256
•
•
•
• : ) RS256
•
•




) Firebase JWT
RS HS
• HMAC: ) HS256
•
•
•
• : ) RS256
•
•
https://pyjwt.readthedocs.io/en/latest/algorithms.html
PyJWT
• TokenAuthentication
• djangorestframework-jwt
• JWT
• JWT
• HMAC
•
Topic 4
HATEOAS
Versioning
Specifying media type
KEYWORDS
• HATEOAS (Hypertext As The Engine Of Application State)
•
•
•
API
Django REST Framework
HATEOAS
Hypertext As The Engine Of Application State
URI 

API DefaultRouter 

HyperLinkedModelSerializer
$ curl http://localhost:8000/api/ | jq .
{
"snippets": "http://localhost:8000/api/snippets/"
"users": “http://localhost:8000/api/users/“
}


• rest_framework.urlpatterns.format_suffix_patterns


• rest_framework.urlpatterns.format_suffix_patterns 

$ curl -H 'Accept: text/html' <your api endpoint>
BrowsableAPIRenderer
$ curl -u user:pass -d '{}' 
> http://127.0.0.1:8000/api/snippets/ | jq .
{
"title": [
" "
],
"created_by": [
" "
]
}
example.com/v1.0/snippets

example.com/snippets?v=2.0
v1.example.com/snippets
Accept: application/json; version=3.0
•
•
• JWT
•
THANK YOU

Django REST Framework における API 実装プラクティス | PyCon JP 2018