Tout d'abord, connexion est un framework API-first développé par Zalando. Bien qu'il ait été construit à l'origine au-dessus de Flask, connexion a ensuite été étendu pour fonctionner avec d'autres frameworks web (asynchrones) tels que aiohttp.
Avec connexion, vous écrivez d'abord votre contrat d'API, en utilisant la norme Swagger/OpenAPI. Ensuite, les points de terminaison que vous avez définis seront mis en correspondance avec vos fonctions de vue Python, ce qui garantit que votre code Python fait ce que votre contrat d'API indique qu'il fait.
Cela le rend assez unique dans le paysage des frameworks web Python, car la plupart des autres outils partent de votre code et non l'inverse.
API-first (ou contract-first) signifie que le développement de votre API REST commence en dehors de votre code (Python). Vous définissez d'abord le comportement de votre API à l'aide d'un langage de spécification standard (Swagger/OpenAPI dans le cas présent). Vous pouvez ensuite consulter les parties prenantes et les consommateurs de votre API avant de commencer la mise en œuvre proprement dite.
Cette approche contraste avec l'approche "code-first" (également appelée "implementation-first"), qui consiste à penser et à écrire l'implémentation. Ensuite, vous pouvez générer la documentation de votre API à l'aide de la norme OpenAPI.
Chez ML6, nous aimons utiliser l'approche API-first pour travailler avec nos clients. Cela nous permet de nous concentrer sur le problème commercial que nous essayons de résoudre sans nous mêler des détails de la mise en œuvre : il y a une séparation claire entre la définition ("quoi") et la mise en œuvre ("comment"). En outre, plusieurs équipes (par exemple les équipes frontend et backend) peuvent travailler en parallèle sur la base du contrat qui a été convenu. Avec le code d'abord, une partie doit attendre que l'autre partie ait terminé l'implémentation. Par exemple, l'équipe frontale peut facilement simuler le backend en utilisant la spécification de l'API.
En outre, la plupart des autres frameworks utilisent des décorateurs pour faire correspondre vos fonctions Python aux points de terminaison, ce qui risque d'encombrer votre code en mélangeant la "logique" REST avec votre logique d'application dans le même fichier. Dans connexion, vous n'écrivez que votre logique d'application, et connexion relie votre fonction au point de terminaison correspondant dans votre définition de l'API.
Pour des informations plus détaillées sur les avantages de l'adoption d'une approche API-first, vous pouvez lire les excellentes directives RESTful API de Zalando ou cet article de blog de Google.
Un autre avantage de la méthode API-first est qu'elle s'intègre parfaitement au processus de déploiement de votre API sur Google Cloud Platform, pour des outils tels que Google Cloud Endpoints et Google Cloud API Gateway, qui utilisent la spécification OpenAPI. Vous pouvez ensuite héberger la documentation de votre API sur le portail des développeurs Endpoints (en utilisant un IAM et une sécurité différents de ceux de votre API elle-même).
Cela s'applique également à d'autres fournisseurs de services en nuage. Par exemple, vous pouvez également l'utiliser pour déployer votre API sur Amazon API Gateway ou Azure API Management. Lorsque vous utilisez une approche "code-first", vous devez exécuter votre application pour extraire le contrat d'API avant de pouvoir le déployer, ce qui peut s'avérer fastidieux et potentiellement source de problèmes. Par exemple, la spécification générée ne correspond pas exactement à ce que vous aviez prévu, ou votre application nécessite une connexion à une base de données, que vous devez alors simuler. En adoptant un cadre API-first, le contrat API devient la "vérité centrale", ce qui est plus robuste et plus sûr car il devient plus clair sur ce que l'API doit faire et ce qu'elle ne doit pas faire, et comment l'implémentation peut potentiellement s'en écarter.
Examinons de plus près en quoi connexion est différent en le comparant à un framework web populaire et en plein essor : FastAPI. Notre objectif n'est pas d'affirmer que l'un est nécessairement meilleur que l'autre, mais plutôt d'identifier les avantages et les inconvénients de l'approche de chaque framework.
Les différences fonctionnelles entre connexion et FastAPI découlent de la différence de "vision" : connexion est axée sur l'API, tandis que FastAPI est axée sur le code.
*Note : l'objectif de pydantic est d'analyser des données en Python, ce n'est pas le cas de pydantic. pas pas la même chose que la validation des données. Par exemple, la chaîne "1" peut être analysée comme un entier avec la valeur 1, mais ce n'est pas un entier valide en soi. Cela peut entraîner des comportements surprenants dans votre API. Voir cette question pour plus d'informations.
Les autres différences (sans rapport avec l'approche API-first/code-first) sont les suivantes :
Jusqu'à présent, nous avons discuté des différences fonctionnelles. Bien sûr, nous voulons savoir ce que cela signifie réellement en termes de chiffres concrets. Pour ce faire, nous avons effectué un petit exercice de benchmarking pour voir la différence de débit et de latence entre connexion (avec Flask) et FastAPI pour un seul point d'extrémité d'une application qui fonctionne en production.
Il est important de noter que notre objectif n'est pas d'effectuer une comparaison générale entre les deux cadres. Nous voulons plutôt vérifier quelles sont les différences concrètes pour notre application particulière. Vous ne devriez jamais vous fier à des benchmarks externes utilisant des exemples simples et synthétiques, mais plutôt exécuter votre propre benchmark sur votre application lorsque vous évaluez différentes options. Ce billet de blog explique pourquoi plus en détail. Dans notre cas, l'API devra exécuter des requêtes contre une base de données SQL, et peut donc bénéficier d'un code asynchrone pour éviter de bloquer en attendant que la base de données renvoie les résultats.
Dans notre cas, nous examinons deux cas différents : le cas synchrone et le cas asynchrone. La configuration de notre benchmark consiste en gunicorn avec 10 workers (en utilisant le worker standard pour flask, et uvicorn.workers.UvicornWorker pour les frameworks asynchrones). Dans le cas asynchrone, nous utilisons également la bibliothèque gevent, qui permet d'écrire du code synchrone avec Flask et monkeypatch le code sous-jacent de sorte qu'il devienne asynchrone sans que nous ayons à nous soucier de la boucle d'événement explicitement.
Notez que nous utilisons une implémentation de la connexion avec Quart qui n'a pas été entièrement intégrée et testée.
Pour FastAPI, en utilisant async def, vous forcez le framework à exécuter la fonction dans la boucle d'événement principale. Vous devez donc veiller à ne pas effectuer de tâches bloquantes. Si vous utilisez regular def, FastAPI le planifiera sur un ThreadpoolExecutor séparé, donc vous n'avez pas besoin de vous soucier du blocage/non-blocage dans ce cas. Comme effet secondaire, cela nous permet également de "forcer" un comportement synchrone avec FastAPI (qui est un framework asynchrone).
En regardant les chiffres, nous pouvons voir que dans le cadre synchrone, connexion + flask surpassent FastAPI synchrone à la fois en termes de débit et de latence. Pour le cas asynchrone, nous constatons que FastAPI surpasse connexion + quart (note : il est possible qu'il y ait encore des optimisations possibles dans l'implémentation de Quart pour la connexion). Cependant, l'utilisation de gevent donne des résultats encore meilleurs et est le grand gagnant de cet exercice.
Chez ML6, nous aimons "faire plutôt que parler" et nous essayons donc d'aider et de contribuer à l'open source quand c'est possible, et c'est pourquoi nous voulons aider à maintenir connexion. C'est pourquoi nous voulons aider à maintenir connexion, car nous pensons que c'est toujours le bon outil pour nous, s'il est bien entretenu.
L'un des grands changements que nous avons proposés et qui a déjà été incorporé dans connexion est la prise en charge de plusieurs systèmes d'authentification en mode ET logique, ce qui permet d'utiliser, par exemple, deux clés API en même temps.
En outre, nous venons d'obtenir les autorisations nécessaires pour publier de nouvelles versions sur PyPI, ce qui était un obstacle jusqu'à présent. Les prochaines étapes consistent à définir l'orientation future et la feuille de route de connexion en collaboration avec la communauté(https://github.com/zalando/connexion/issues/1395). La grande question pour l'avenir de connexion est de savoir où il crée le plus de valeur pour ses utilisateurs : en tant que framework, ou plutôt en tant qu'intergiciel. Nous sommes ouverts à toutes les contributions, car cette question est importante pour tous les utilisateurs (potentiels) de connexion, alors n'hésitez pas à nous faire part de vos réflexions sur le sujet Github.