REST in peace
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9170809/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9170814/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9170819/pasted-from-clipboard.png)
Python
Roadmap
- Python
- Requests
- Django
- Django REST Framework
- REST et OpenAPI
- sécurité des WS
ATTENTION!
Ceci n'est qu'un itinéraire prévu...
![](https://cdna.artstation.com/p/assets/images/images/015/298/970/large/lena-voronina-jungle-map2.jpg?1547830200)
Python
Le langage
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9170809/pasted-from-clipboard.png)
Objectifs
- Maîtrise suffisante du langage pour les WS
- éviter les slides sur la syntaxe arithmétique
- Montrer les qualités du langage
- donner les sources nécessaires à plus de (auto) formation
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9110287/pasted-from-clipboard.png)
Historique
- Created by Guido Van Rossum in 1990
- Promoted himself as BDFL : Benevolent Dictator For Life
- First release of the backward incompatible release 3.0 in 2008
- Last release of the 2.7 version in 2010
(Mais très court! Promis...)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9171089/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9178348/pasted-from-clipboard.png)
Version
La version du langage utilisé
(Aujourd'hui, nous utilisons la version 3.10)
Interpréteur
L'implémentation du langage.
Il en existe plusieurs:
- CPython
- IronPython
- PyPy
- Jython
- ...
Distribution
Certaines librairies sont difficiles à installer sous Windows.
Une distribution comme Anaconda permet de gagner du temps.
Anatomie
- Multiparadigme
- impératif, fonctionnel, orienté objet, orienté aspect
- Interprété (OS Portable)
- Typage Dynamique
- Garbage collector
- Lisible...
Sinon, c'est mieux perçu par la pratique...
L'interpréteur
- python.exe
- utilisation du -m
- gestion des variables / objets
- utilisation de "_"
- pas besoin de "print()"
Types primitifs
- typage dynamique mais fort!: type()
- int, float, bool, None
- str (+raw)
- print()
- [] omniprésent!
- bytes
- decode()
NB: TOUT est objet en Python
Les listes
- instanciation
- indexation
- slices (get,set), copy
- négatifs, steps
- compréhension
- méthodes
- append(), sort[ed]()
- opérateurs
- in
- +,*,...
- idiome: range(len()), enumerate()
Les dictionnaires
- instanciation
- indexation
- compréhension
- méthodes
- .items(), .setdefault()
- opérateurs
- in, |, ...
- idiome: dict(zip())
Consonnes / voyelles
Les tuples et les sets
- instanciation
- indexation
- compréhension
- comparaison avec list et dict...
utilisation de "for" pour tous
Python est basé sur les "protocoles" => duck-typing
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180021/pasted-from-clipboard.png)
Les fonctions
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180039/pasted-from-clipboard.png)
def say_hello():
"""
documentation optionnelle (donc indispensable)
appelée 'docstring'.
"""
return "Hello world!"
print(say_hello())
Déclaration
- snake-case
- retourne "None" par défaut.
- "pass"
Scope
(visibilité des variables)
l'appel d'une fonction génère une nouvelle table des symboles contenant:
- symboles "built-in"
- variables globales (du module)
- variables des scopes supérieurs
- (une fonction peut être définie dans une autre => closure)
- paramètres de la fonction
- variables locales
Paramètres
déclarations dans l'ordre:
- paramètres positionnels obligatoires
- paramètres positionnels optionnels
- (avec valeur par défaut)
- paramètres positionnels additionnels
- *args
- paramètres nommés additionnels
- **kwargs
Lors de l'appel => list+dict unpacking
Exercice product()
Ecrire une fonction de multiplication vérifiant:
-
multiply([8, 2, 3, -1, 7]) == -336
-
multiply([8, 2, 3, -1, 7]) == multiply(8, 2, 3, -1, 7)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180023/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9182892/pasted-from-clipboard.png)
open()
- encoding
- str <=> bytes
- module io
- utilisation de "with"
private String open(String path) throws IOException {
InputStream inputStream = null;
try {
File file = new File(classLoader.getResource(path).getFile());
inputStream = new FileInputStream(file);
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = br.readLine()) != null) {
resultStringBuilder.append(line).append("\n");
}
return resultStringBuilder.toString();
}
finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
![](https://media.giphy.com/media/w3J7mstYCISqs/giphy.gif)
Les lambdas
Très utiles comme paramètres d'autres fonctions:
- sorted
- filter
- map (préférez une compréhension)
- reduce (désormais dans functools)
pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
sorted(pairs, key=lambda pair: pair[1])
Les exceptions
- sont des objets...
- try/except/finally
- with
- (context managers)
- "gérées le plus tard possible."
Les modules
- "batteries included"
- math, os, sys, logging, argparse, ...
- package manager (pip)
- import, from, as
- packages
- __init__.py
- "__main__" + sys.argv
- sont des objets (attributs dynamiques).
- mais le "monkey patching" est un grand pouvoir qui implique...
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180023/pasted-from-clipboard.png)
Exercice "prime"
Ecrire un module de manipulation des nb premiers:
- chargement d'une liste de nombres premiers (depuis un fichier)
- écriture d'un fichier au même format (csv ou autre)
- recherche de nombres premiers depuis le dernier de la liste
POO
(mais pas trop)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180290/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180330/pasted-from-clipboard.png)
Les classes
class Bird:
def __init__(self, mood="Happy", size=0):
self.mood = mood
self.size = size
def fly(self):
self.mood = "Happy"
print("Look at me! I'm flying!")
def kick(self):
self.mood = "Angry"
Les définitions de classes sont exécutées pour produire une classe
(qui est un objet...)
Les classes
woody = Bird(mood="neutral")
type(woody) == Bird # True
Les classes sont appelées pour créer des instances.
Ca ressemble pas mal à des fonctions...
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180354/pasted-from-clipboard.png)
Héritage
class Duck(Bird):
def quack(self):
print "Quack, quack!"
def kick(self):
self.quack()
super(Duck, self).kick()
daffy = Duck()
type(daffy) == Duck
# Polymorphism
isinstance(daffy, Bird) == True
daffy.fly()
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180375/pasted-from-clipboard.png)
Héritage
# Let's adopt another duck:
donald = Duck(size=10)
# How is it linked to daffy?
donald.nephews = ["Huey", "Dewey", "Louie"]
daffy.nephews #NameError
donald.__class__.face = "Duck-billed"
donald.face # "Duck-billed"
daffy.face # "Duck-billed"!!!
# How is it linked to woody?
woody.face # NameError
woody.__class__.personality = "funny"
woody.personality # "funny"
donald.personality # "funny"
# What happens if I do:
daffy.personality = "evil" #???
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180407/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180410/pasted-from-clipboard.png)
Duck-typing
class Goose(Bird): # A Goose is NOT a Duck
def quack(self):
print("Quack like a Goose")
def make_it_quack(o):
o.quack()
sauvage = Goose()
make_it_quack(sauvage)
make_it_quack(donald) #It works!
- Duck-typing := pas de vérification de type
- => définition de "protocoles" plutôt que d'interfaces
Méthodes magiques
des protocoles standards, définis par le langage.
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180469/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9193746/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180023/pasted-from-clipboard.png)
Exercice magique
- Choisissez un thème:
- fruits, formes géométriques, véhicules…
- définir ce que signifie d'itérer, d'ajouter, etc... des objets de ce type
c'est magique aussi parce que ça marche avec tout…
Et la performance!
On en parle?
![](https://i.imgflip.com/5xd5ei.jpg)
Ce que nous ne verrons pas cette fois...
- générateurs
- décorateurs
- context managers
- meta classes
- coroutines
- typage statique
- descripteurs
- toute la lib standard
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9180533/pasted-from-clipboard.png)
concepts
- Dataclasses
-
async def, with, for + await
- __await__ -> awaitable (returns an iterable)
- async def -> coroutine (are awaitable!)
- __aiter__ -> async iterable (return async iterator)
- __anext__ -> async iterator (returns awaitable)
- __aenter/exit__-> async ctxt mng (return awaitables)
- positional , / , pos-or-kw , * , kw
- single dispatch
- slice: [:] -> slice obj in __getitem__
-
type hints
- Generic[], TypeVar()
Requests
(HTTP for humans)
#pip install requests
response = requests.get(
"http://www.google.fr",
proxies={"http": "http://192.168.3.3:8080"},
)
# OU (avec cookies jar)
session = requests.Session()
session.proxies={"http": "http://192.168.3.3:8080"}
response = session.get("http://www.google.fr")
#pip install beautifulsoup4
from bs4 import BeautifulSoup
soup = BeautifulSoup(response.content)
soup.find_all("a")
![](https://docs.python-requests.org/en/latest/_static/requests-sidebar.png)
Django
Un framework pour les gouverner tous
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9170814/pasted-from-clipboard.png)
Les concepts
Possède des modules pour gérer:
- projets / applications
- vues / URLs
- modèles / migrations
- administration (backoffice)
- tests
- templates
- formulaires
- ...
+ Sécurité par défaut
Installation
# creation environement virtuel
python -m venv .env
. .env/Scripts/activate
# installation
pip install Django
# Vérification
python -m django --version
Vues
# création projet
django-admin startproject demodj .
# création app
python manage.py startapp demo
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world!")
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
# add to server's urls.py:
# path('demo/', include('demo.urls')),
Modèles, ORM, Migrations
python manage.py startapp drvapp
# register in settings.py
# 'default': {
# 'ENGINE': 'django.db.backends.mysql',
# 'NAME': 'DRVAPP_CENTRAL_DATAS',
# 'USER': 'inspect',
# 'PASSWORD': '1nspect',
# 'HOST': '10.34.2.8',
# 'PORT': '3306',
# },
python manage.py inspectdb > drvapp/models.py
# edit generated models.py
python -Xutf8 manage.py dumpdata drvapp -o data.json
# back to default db
python manage.py makemigrations
python manage.py migrate
python manage.py loaddata data.json
python manage.py shell
Admin (backoffice)
from .models import Tournee, Point, Colis
admin.site.register(Tournee)
admin.site.register(Point)
admin.site.register(Colis)
# Et beaucoup plus:
# https://docs.djangoproject.com/en/4.0/intro/tutorial07/
python manage.py createsuperuser
Vues (classes)
from django.views import generic
class IndexView(generic.ListView):
template_name = 'wsdrvapp/index.html'
def get_queryset(self):
return Tournee.objects.order_by('-damj')[:5]
class DetailView(generic.DetailView):
model = Tournee
template_name = 'wsdrvapp/detail.html'
app_name = "wsdrvapp"
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
]
Django REST Framework
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1590388/images/9170819/pasted-from-clipboard.png)
REST
(Representational State Transfer)
Contraintes
- client/serveur
- sans état
- on transfère une représentation de la ressource à un instant donné
- identification des ressources
- HATEOAS (navigation)
Avantages
- découplage
- réactivité
- standardisation
- accessibilité (HTTP)
- scalabilité horizontale
Les concepts DRF
Possède des modules pour gérer:
- parsing / rendering
- serializers / validators
- viewsets
- routeurs
- authentication
- permissions
- pagination
- filtering
- throttling...
Installation
# Dans un projet django
pip install djangorestframework
pip install markdown # Markdown support for the browsable API.
pip install django-filter # Filtering support
# 'rest_framework' dans INSTALLED_APPS
# settings specifiques dans REST_FRAMEWORK = {}
# path('api-auth/', include('rest_framework.urls'))
Serializers
from rest_framework import serializers
from .models import Tournee
class TourneeSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Tournee
fields = '__all__'
from wsdrvapp.models import Tournee
from wsdrvapp.serializers import TourneeSerializer
from pprint import pprint
t = Tournee.objects.first()
s = TourneeSerializer(t, context={'request':None})
pprint(s.data)
Viewsets
from rest_framework import viewsets
from .models import Point, Tournee
from .serializers import TourneeSerializer
class TourneeViewSet(viewsets.ModelViewSet):
queryset = Tournee.objects.all()
serializer_class = TourneeSerializer
Router
from wsdrvapp.views import TourneeViewSet
from rest_framework import routers
router = routers.DefaultRouter()
router.register('tournee', TourneeViewSet)
urlpatterns = [
# ...
path('api/', include(router.urls)),
]
Permissions
(authentication)
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
],
}
from rest_framework import schemas
urlpatterns = [
# ...
path('api-auth/', include('rest_framework.urls')),
]
Pagination
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 5,
}
Filtering (1/2)
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter',
),
}
class TourneeViewSet(viewsets.ModelViewSet):
queryset = Tournee.objects.all()
serializer_class = TourneeSerializer
filterset_fields = ('num', 'bl')
search_fields = ['num', 'date', 'bl', 'loccode']
Filtering (2/2)
class PointViewSet(viewsets.ModelViewSet):
queryset = Point.objects.all()
serializer_class = PointSerializer
filterset_class = PointFilter
search_fields = ['cp', 'tournee__num']
from django_filters import rest_framework as filters
from .models import Point
class PointFilter(filters.FilterSet):
min_lat = filters.NumberFilter(field_name="lat", lookup_expr='gte')
max_lat = filters.NumberFilter(field_name="lat", lookup_expr='lte')
min_lon = filters.NumberFilter(field_name="lon", lookup_expr='gte')
max_lon = filters.NumberFilter(field_name="lon", lookup_expr='lte')
class Meta:
model = Point
fields = ['cp']
OpenAPI / Schemas
from rest_framework import schemas
urlpatterns = [
# ...
path('openapi', schemas.get_schema_view(
title="WSDriverApp",
description="API for all things …",
version="1.0.0"
), name='openapi-schema'),
]
Swagger UI
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path('api-auth/', include('rest_framework.urls')),
path('api/', include(router.urls)),
path('openapi', schemas.get_schema_view(
title="WSDriverApp",
description="API for all things …",
version="1.0.0"
), name='openapi-schema'),
path('swagger-ui', TemplateView.as_view(
template_name='wsdrvapp/swagger-ui.html',
extra_context={'schema_url':'openapi-schema'}
), name='swagger-ui'),
]
+ un template
Throttling
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '5/min',
'user': '1000/day'
}
}
Parsing / Rendering
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
'rest_framework_yaml.parsers.YAMLParser',
],
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
'rest_framework_yaml.renderers.YAMLRenderer',
],
}
pip install djangorestframework-yaml
Merci ^^
![](https://dl.airtable.com/.attachments/2f7c668073cee9ddcb71ba2091a0ef2a/ad0d0c80/KDnmlxQ.png)
Merci ^^
Python
By Olivier DUPOUY
Python
a generic but complete introduction to python programming
- 47