MongoDB

MongoDB

MongoDB is a scalable, high-performance, open source, document-oriented NoSQL database. It supports a large number of languages and application development platforms.
Hong  Nhung

Hong Nhung

1660739520

Cách Kết Nối MongoDB Với ứng Dụng Node.js Trong Kubernetes

Trong hướng dẫn ngắn gọn này, Chúng tôi sẽ chia sẻ Cách kết nối MongoDB với một ứng dụng Node.js trong Kubernetes với các bước theo từng bước.

Triển khai MongoDB dưới dạng cơ sở dữ liệu được lưu trữ trên đám mây

Bài viết trước đã thiết lập quyền truy cập giữa MongoDB Atlas và cụm OpenShift của bạn. Nếu bạn đã thực hiện thành công các bước đó, bạn đã sẵn sàng triển khai cơ sở dữ liệu MongoDB được lưu trữ trên đám mây trong cụm như sau:

  1. Trong bảng điều khiển OpenShift, hãy truy cập dạng xem Topo bằng cách chọn Nhà phát triển → Topo từ thanh bên trái.
  2. Chọn dự án mà bạn muốn triển khai cơ sở dữ liệu đám mây bằng cách chọn, từ trên cùng của thanh bên trái, Nhà phát triểnCấu trúc liên kết → Dự án . Từ menu thả xuống, hãy chọn dự án của bạn.
  3. Trong menu bên trái, nhấp vào + Thêm → Cơ sở dữ liệu được lưu trữ trên đám mây → Dịch vụ cơ sở dữ liệu đám mây của MongoDB Atlas → Thêm vào cấu trúc liên kết . Chọn phiên bản cơ sở dữ liệu của bạn và nhấp vào Thêm vào cấu trúc liên kết → Tiếp tục .
  4. Sau khi kết nối thành công, bạn sẽ được đưa đến dạng xem Topo, nơi cơ sở dữ liệu được lưu trữ trên đám mây được triển khai và hiển thị (Hình 1).

Chế độ xem Topo cho thấy rằng MongoDB Atlas hiện có thể truy cập được trong cụm của bạn.

Hình 1: Chế độ xem Topo cho thấy rằng MongoDB Atlas hiện có thể truy cập được trong cụm của bạn.

Triển khai ứng dụng Node.js trong OpenShift

Có một số cách để triển khai ứng dụng Node.js trong OpenShift: Thông qua ocgiao diện dòng lệnh OpenShift (CLI), odoCLI, bảng điều khiển OpenShift, v.v. Bài viết này đề cập đến hai tùy chọn: Bảng điều khiển OpenShift và Nodeshift , một gói NPM.

Triển khai thông qua bảng điều khiển OpenShift

Từ góc độ Nhà phát triển , chọn + Thêm → Nhập từ Git .

Trong trường url kho lưu trữ Git , hãy đặt URL kho lưu trữ thành https://github.com/nodeshift-blog-examples/kube-service-bindings-examples. Đây là kho lưu trữ ví dụ về kube-service-bindings được duy trì bởi nhóm của chúng tôi; nó chứa ứng dụng Node.js mà bạn đang triển khai trong bài viết này.

Mở rộng Hiển thị các tùy chọn Git nâng cao . Trên trường Dir ngữ cảnh , hãy đặt giá trị thành src/mongodb, là đường dẫn của thư mục con nơi đặt ứng dụng Node.js của bạn.

Trên Hình ảnh trình dựng , chọn Node.js và nhấp vào Tạo .

Triển khai thông qua Nodeshift

Mở một thiết bị đầu cuối và sao chép kho lưu trữ git:

git clone https://github.com/nodeshift-blog-examples/kube-service-bindings-examples.git
$ cd ./kube-service-bindings-examples/src/mongodb

Cài đặt Nodeshift trên toàn cầu:

$ npm install -g nodeshift

Để tìm thông tin đăng nhập được yêu cầu bởi lệnh tiếp theo mà bạn sẽ sử dụng, hãy truy cập bảng điều khiển OpenShift của bạn. Ở góc trên bên phải, nhấp vào tên người dùng của bạn. Một danh sách thả xuống sẽ xuất hiện. Nhấp vào Sao chép lệnh đăng nhập (Hình 2), lệnh này sẽ chuyển bạn đến một trang khác. Sau đó nhấp vào thông báo hiển thị để hiển thị tên người dùng, mật khẩu và thông tin đăng nhập máy chủ để đăng nhập với Nodeshift.

Dưới tên của bạn trong bảng điều khiển, bạn có thể lấy thông tin đăng nhập.

Hình 2: Dưới tên của bạn trong bảng điều khiển, bạn có thể lấy thông tin đăng nhập.

Sử dụng các thông tin đăng nhập này, bây giờ bạn có thể đăng nhập vào cụm OpenShift của mình bằng Nodeshift:

$ nodeshift login --username=developer --password=password --server=https://api.server

Triển khai ứng dụng Node.js với Nodeshift thông qua lệnh sau, thay thế tên không gian tên bằng tên dự án cụ thể của bạn:

$ nodeshift --namespace.name=<selected-project>

Ứng dụng của bạn sẽ được triển khai và hiển thị trong dạng xem Topo, như trong Hình 3.

Ứng dụng Node.js xuất hiện trong dạng xem Topo.

Hình 3: Ứng dụng Node.js xuất hiện trong dạng xem Topo.

Thiết lập kết nối giữa ứng dụng Node.js và cơ sở dữ liệu MongoDB

Bước cuối cùng trong loạt bài này là thiết lập kết nối giữa ứng dụng Node.js của bạn và cơ sở dữ liệu MongoDB, mà chúng ta sẽ thực hiện trong phần này.

Nhà điều hành ràng buộc dịch vụ

Tại thời điểm này, hai trường hợp sẽ hiển thị trong dạng xem Topo của bạn: ứng dụng Node.js và kết nối với cá thể MongoDB của bạn trong Atlas (Hình 4).

Dạng xem Topo hiển thị cả ứng dụng Node.js và cơ sở dữ liệu MongoDB bên ngoài.

Hình 4: Dạng xem Topo cho thấy cả ứng dụng Node.js và cơ sở dữ liệu MongoDB bên ngoài.

Để thiết lập kết nối giữa các trường hợp này, bạn sẽ sử dụng Nhà điều hành ràng buộc dịch vụ để chia sẻ thông tin xác thực và kube-service-bindings để phân tích cú pháp các thông tin xác thực đó (dữ liệu ràng buộc).

Bạn có thể tạo Ràng buộc dịch vụ theo hai cách khác nhau:

  • Kéo một dòng trong dạng xem Topo giữa hai dịch vụ hỗ trợ (ứng dụng Node.js và MongoDB).
  • Áp dụng tệp YAML chỉ định ràng buộc dịch vụ.

Chúng tôi sẽ đi với tùy chọn đầu tiên, trong trường hợp của chúng tôi là nhanh hơn và dễ dàng hơn.

Di chuột qua ứng dụng Node.js trong dạng xem Topo. Một mũi tên sẽ xuất hiện. Kéo mũi tên từ ứng dụng Node.js vào vòng tròn xung quanh cá thể MongoDB. Chú giải công cụ sẽ hiển thị có nội dung Tạo liên kết dịch vụ . Thả nút chuột và một hộp bật lên sẽ cho phép bạn chỉ định tên của ràng buộc dịch vụ. Nhấp vào Tạo ràng buộc . Vùng chứa của ứng dụng Node.js sẽ khởi động lại ngay lập tức (Hình 5).

Kiểm tra môi trường của ứng dụng Node.js bằng cách nhấp vào vùng chứa ứng dụng Node.js trong dạng xem Topo. Trong thanh bên bên phải, nhấp vào Tài nguyên → Xem Nhật ký (Phần nhóm) và truy cập tab Môi trường . Biến SERVICE_BINDING_ROOTmôi trường nên được thiết lập, như thể hiện trong Hình 6.

đối với các ràng buộc dịch vụ

Bước cuối cùng là đọc dữ liệu ràng buộc trong thư mục được chỉ định bởi SERVICE_BINDING_ROOTbiến và chuyển dữ liệu đến máy khách MongoDB để thiết lập kết nối với cơ sở dữ liệu MongoDB. Ứng dụng Node.js của bạn đã có kube-service-bindings như một phần phụ thuộc. Vì vậy, việc gọi getBinding()hàm, như được hiển thị trong đoạn mã JavaScript sau, thực hiện tất cả các công việc khó khăn là phân tích cú pháp, làm sạch và chuyển đổi dữ liệu liên kết thành định dạng có thể sử dụng được cho ứng dụng khách MongoDB:

const { MongoClient } = require("mongodb");

const serviceBindings = require("kube-service-bindings");

const { url, connectionOptions } = serviceBindings.getBinding("MONGODB", "mongodb");

const mongoClient = new MongoClient(url, connectionOptions);

Đó là nó. Bằng cách truy cập URL của ứng dụng Node.js (nhấp vào biểu tượng hộp mũi tên trên nút), bạn có thể thực hiện các thao tác CRUD đơn giản thông qua giao diện người dùng trên cơ sở dữ liệu.

Tích hợp dễ dàng hơn với các dịch vụ trên Kubernetes

Trong năm qua, nhóm của chúng tôi đã tích cực phát triển các ràng buộc dịch vụ kube, giúp các nhà phát triển có ít hoặc không có kinh nghiệm trong việc quản lý các ứng dụng chứa trong container dễ dàng chia sẻ thông tin đăng nhập giữa các dịch vụ hỗ trợ một cách dễ dàng hơn.

Bổ sung cho công việc phát triển kube-service-bindings , nhóm của chúng tôi cung cấp các ví dụ cho hầu hết các khách hàng được hỗ trợ bởi kube-service-bindings, hướng dẫn sử dụng kube-service-bindings và mô tả về cách triển khai nhiều dịch vụ hỗ trợ thông qua Nodeshift trong môi trường Kubernetes và OpenShift.

Loạt bài viết này đã chỉ ra những ứng dụng khách nào được hỗ trợ và cách thức hoạt động của cả ràng buộc dịch vụ và ràng buộc dịch vụ kube. Chúng tôi đã hướng dẫn bạn toàn bộ chu trình triển khai dịch vụ sao lưu ứng dụng Node.js bằng cách sử dụng SBO và kube-service-bindings, chia sẻ và phân tích cú pháp thông tin xác thực cho kết nối giữa ứng dụng Node.js và cơ sở dữ liệu MongoDB. kube-service-bindings đọc, phân tích cú pháp và chuyển đổi dữ liệu ràng buộc do Nhà điều hành Service Binding dự kiến, trả về dữ liệu ở dạng được ứng dụng MongoDB trực tiếp sử dụng.

Để giúp bạn sử dụng kube-service-bindings trong các kiểu triển khai khác, chúng tôi đã cung cấp thêm các ví dụ về Node.js. Chúng tôi hy vọng bạn thấy bài viết này thú vị và bây giờ đã hiểu rõ hơn về kube-service-bindings và các ràng buộc dịch vụ nói chung.

Liên kết: https://developers.redhat.com/articles/2022/08/16/connect-mongodb-nodejs-application-kube-service-bindings#deploy_mongodb_as_a_cloud_hosted_database

#node #nodejs #mongodb #database #kubernetes

Cách Kết Nối MongoDB Với ứng Dụng Node.js Trong Kubernetes
Thierry  Perret

Thierry Perret

1660732278

Comment Connecter MongoDB à Une Application Node.js Dans Kubernetes

Dans ce bref guide, nous partagerons comment connecter MongoDB à une application Node.js dans Kubernetes étape par étape.

Déployer MongoDB en tant que base de données hébergée dans le cloud

L'article précédent a configuré l'accès entre MongoDB Atlas et votre cluster OpenShift. Si vous avez suivi ces étapes avec succès, vous êtes prêt à déployer une base de données MongoDB hébergée dans le cloud dans le cluster comme suit :

  1. Dans la console OpenShift, accédez à la vue Topologie en sélectionnant Développeur → Topologie dans la barre latérale gauche.
  2. Sélectionnez le projet dans lequel vous souhaitez déployer la base de données cloud en sélectionnant, en haut de la barre latérale gauche, DéveloppeurTopologieProjet . Dans le menu déroulant, sélectionnez votre projet.
  3. Dans le menu latéral de gauche, cliquez sur +Ajouter→Base de données hébergée dans le cloud→MongoDB Atlas Cloud Database Service→Ajouter à la topologie . Sélectionnez votre instance de base de données et cliquez sur Ajouter à la topologie→Continuer .
  4. Une fois la connexion établie, vous accédez à la vue Topologie, où la base de données hébergée dans le cloud est déployée et visible (Figure 1).

La vue Topologie montre que MongoDB Atlas est désormais accessible dans votre cluster.

Figure 1 : La vue Topologie montre que MongoDB Atlas est désormais accessible dans votre cluster.

Déployer l'application Node.js dans OpenShift

Il existe plusieurs façons de déployer une application Node.js dans OpenShift : via l' ocinterface de ligne de commande (CLI) OpenShift, la odoCLI, la console OpenShift, etc. Cet article couvre deux options : la console OpenShift et Nodeshift , un package NPM.

Déployer via la console OpenShift

Du point de vue du développeur, sélectionnez +Ajouter→Importer depuis Git .

Dans le champ URL du référentiel Git , définissez l'URL du référentiel sur https://github.com/nodeshift-blog-examples/kube-service-bindings-examples. Il s'agit d'un référentiel d'exemples kube-service-bindings maintenu par notre équipe ; il contient l'application Node.js que vous déployez dans cet article.

Développez Afficher les options avancées de Git . Dans le champ Context dir , définissez la valeur sur src/mongodb, qui est le chemin du sous-répertoire où se trouve votre application Node.js.

Sur Builder Image , sélectionnez Node.js et cliquez sur Create .

Déployer via Nodeshift

Ouvrez un terminal et clonez le dépôt git :

git clone https://github.com/nodeshift-blog-examples/kube-service-bindings-examples.git
$ cd ./kube-service-bindings-examples/src/mongodb

Installez Nodeshift globalement :

$ npm install -g nodeshift

Pour trouver les identifiants de connexion requis par la prochaine commande que vous utiliserez, visitez votre console OpenShift. Dans le coin supérieur droit, cliquez sur votre nom d'utilisateur. Une liste déroulante apparaîtra. Cliquez sur Copier la commande de connexion (Figure 2), qui vous transfère vers une autre page. Cliquez ensuite sur Afficher le jeton pour afficher le nom d'utilisateur, le mot de passe et les informations d'identification du serveur pour vous connecter à Nodeshift.

Sous votre nom dans la console, vous pouvez obtenir des identifiants de connexion.

Figure 2 : Sous votre nom dans la console, vous pouvez obtenir des identifiants de connexion.

À l'aide de ces informations d'identification, vous pouvez désormais vous connecter à votre cluster OpenShift avec Nodeshift :

$ nodeshift login --username=developer --password=password --server=https://api.server

Déployez l'application Node.js avec Nodeshift via la commande suivante, en remplaçant le nom de l'espace de noms par le nom de votre projet :

$ nodeshift --namespace.name=<selected-project>

Votre application doit être déployée et visible dans la vue Topologie, comme illustré à la figure 3.

L'application Node.js apparaît dans la vue Topologie.

Figure 3 : L'application Node.js apparaît dans la vue Topologie.

Établir une connexion entre l'application Node.js et la base de données MongoDB

La dernière étape de cette série consiste à établir une connexion entre votre application Node.js et la base de données MongoDB, ce que nous accomplirons dans cette section.

Opérateur de liaison de service

À ce stade, deux instances doivent apparaître dans votre vue Topologie : l'application Node.js et la connexion à votre instance MongoDB dans Atlas (Figure 4).

La vue Topologie affiche à la fois l'application Node.js et la base de données MongoDB externe.

Figure 4 : La vue Topologie affiche à la fois l'application Node.js et la base de données MongoDB externe.

Pour établir une connexion entre ces instances, vous utiliserez l'opérateur de liaison de service pour partager les informations d'identification et kube-service-bindings pour analyser ces informations d'identification (données de liaison).

Vous pouvez créer une liaison de service de deux manières différentes :

  • Faites glisser une ligne dans la vue Topologie entre les deux services de support (l'application Node.js et MongoDB).
  • Appliquez un fichier YAML spécifiant la liaison de service.

Nous allons opter pour la première option, qui dans notre cas est plus rapide et plus facile.

Passez la souris sur l'application Node.js dans la vue Topologie. Une flèche devrait apparaître. Faites glisser la flèche de l'application Node.js vers le cercle autour de l'instance MongoDB. Une info-bulle devrait être visible indiquant Créer une liaison de service . Relâchez le bouton de la souris et une fenêtre contextuelle vous permettra de spécifier le nom de la liaison de service. Cliquez sur Créer une liaison . Le conteneur de l'application Node.js redémarrera immédiatement (Figure 5).

Vérifiez l'environnement de l'application Node.js en cliquant sur le conteneur d'application Node.js dans la vue Topologie. Dans la barre latérale droite, cliquez sur Ressources → Afficher les journaux (section Pods) et visitez l' onglet Environnement . La SERVICE_BINDING_ROOTvariable d'environnement doit être définie, comme illustré à la figure 6.

aux liaisons de service

La dernière étape consiste à lire les données de liaison sous le répertoire indiqué par la SERVICE_BINDING_ROOTvariable et à transmettre les données au client MongoDB pour établir une connexion à la base de données MongoDB. Votre application Node.js a déjà kube-service-bindings comme dépendance. Ainsi, l'appel de la getBinding()fonction, comme indiqué dans l'extrait de code JavaScript suivant, effectue tout le travail difficile d'analyse, de nettoyage et de transformation des données de liaison en un format consommable pour le client MongoDB :

const { MongoClient } = require("mongodb");

const serviceBindings = require("kube-service-bindings");

const { url, connectionOptions } = serviceBindings.getBinding("MONGODB", "mongodb");

const mongoClient = new MongoClient(url, connectionOptions);

C'est ça. En visitant l'URL de l'application Node.js (cliquez sur l'icône représentant une flèche sur le nœud), vous pouvez effectuer des opérations CRUD simples via l'interface utilisateur de la base de données.

Intégration plus facile avec les services sur Kubernetes

Au cours de l'année écoulée, notre équipe a été active dans le développement de kube-service-bindings, ce qui permet aux développeurs peu ou pas expérimentés dans la gestion d'applications conteneurisées de partager en toute sécurité les informations d'identification entre les services de support.

En complément du travail sur le développement de kube-service-bindings , notre équipe fournit des exemples pour la plupart des clients pris en charge par kube-service-bindings, des instructions sur l'utilisation de kube-service-bindings et une description de la façon de déployer une variété de services de support via Nodeshift dans les environnements Kubernetes et OpenShift.

Cette série d'articles a montré quels clients sont pris en charge et comment fonctionnent à la fois une liaison de service et kube-service-bindings. Nous vous avons guidé tout au long du cycle de déploiement d'un service de sauvegarde d'application Node.js à l'aide des liaisons SBO et kube-service, en partageant et en analysant les informations d'identification pour une connexion entre une application Node.js et une base de données MongoDB. kube-service-bindings lit, analyse et transforme les données de liaison projetées par l'opérateur de liaison de service, renvoyant les données sous une forme directement consommable par le client MongoDB.

Pour vous aider à utiliser kube-service-bindings dans d'autres types de déploiements, nous avons fourni des exemples Node.js supplémentaires . Nous espérons que vous avez trouvé cet article intéressant et que vous avez maintenant une meilleure compréhension de kube-service-bindings et des liaisons de service en général.

Lien : https://developers.redhat.com/articles/2022/08/16/connect-mongodb-nodejs-application-kube-service-bindings#deploy_mongodb_as_a_cloud_hosted_database

#node #nodejs #mongodb #database #kubernetes

Comment Connecter MongoDB à Une Application Node.js Dans Kubernetes
Hans  Marvin

Hans Marvin

1660725060

How to Connect MongoDB To A Node.js Application in Kubernetes

In this brief guide, We will share How to Connect MongoDB To A Node.js Application in Kubernetes With Steps by Step.

Deploy MongoDB as a cloud-hosted database

The previous article set up access between MongoDB Atlas and your OpenShift cluster. If you went through those steps successfully, you are ready to deploy a cloud-hosted MongoDB database in the cluster as follows:

  1. In the OpenShift console, visit the Topology view by selecting Developer→Topology from the left sidebar.
  2. Select the project where you would like to deploy the cloud database by selecting, from the top of the left sidebar, DeveloperTopologyProject. From the dropdown menu, select your project.
  3. In the left sidebar menu, click +Add→Cloud-Hosted Database→MongoDB Atlas Cloud Database Service→Add to Topology. Select your database instance and click Add to topology→Continue.
  4. Upon successful connection, you are taken to the Topology view, where the cloud-hosted database is deployed and visible (Figure 1).

See more at: https://developers.redhat.com/articles/2022/08/16/connect-mongodb-nodejs-application-kube-service-bindings#

#node #nodejs #mongodb #database #kubernetes

How to Connect MongoDB To A Node.js Application in Kubernetes
加藤  七夏

加藤 七夏

1660717800

如何將 MongoDB 連接到 Kubernetes 中的 Node.js 應用程序

在這個簡短的指南中,我們將逐步分享如何將 MongoDB 連接到 Kubernetes 中的 Node.js 應用程序。

將 MongoDB 部署為雲託管數據庫

上一篇文章設置了MongoDB Atlas和您的 OpenShift 集群之間的訪問。如果您成功完成了這些步驟,您就可以在集群中部署雲託管的 MongoDB 數據庫,如下所示:

  1. 在 OpenShift 控制台中,通過從左側邊欄中選擇Developer→Topology來訪問 Topology 視圖。
  2. 通過從左側邊欄頂部選擇DeveloperTopologyProject來選擇要部署雲數據庫的項目。從下拉菜單中,選擇您的項目。
  3. 在左側邊欄菜單中,單擊+添加→雲託管數據庫→MongoDB Atlas 雲數據庫服務→添加到拓撲。選擇您的數據庫實例並單擊添加到拓撲→繼續
  4. 成功連接後,您將進入拓撲視圖,其中部署了雲託管數據庫並且可見(圖 1)。

Topology 視圖顯示 MongoDB Atlas 現在可以在您的集群中訪問。

圖 1:拓撲視圖顯示 MongoDB Atlas 現在可以在您的集群中訪問。

在 OpenShift 中部署 Node.js 應用程序

在 OpenShift 中部署 Node.js 應用程序有多種方法:通過ocOpenShift 命令行界面 (CLI)、odoCLI、OpenShift 控制台等。本文介紹了兩個選項:OpenShift 控制台和Nodeshift,一個 NPM 包。

通過 OpenShift 控制台部署

開發人員的角度來看,選擇+Add→Import from Git

Git Repo url字段中,將存儲庫 URL 設置為https://github.com/nodeshift-blog-examples/kube-service-bindings-examples. 這是我們團隊維護的kube-service-bindings 示例存儲庫;它包含您在本文中部署的 Node.js 應用程序。

展開顯示高級 Git 選項。在Context dir字段中,將值設置為src/mongodb,這是您的 Node.js 應用程序所在的子目錄的路徑。

Builder Image上,選擇Node.js並單擊Create

通過 Nodeshift 部署

打開終端並克隆 git 存儲庫:

git clone https://github.com/nodeshift-blog-examples/kube-service-bindings-examples.git
$ cd ./kube-service-bindings-examples/src/mongodb

全局安裝 Nodeshift:

$ npm install -g nodeshift

要查找您將使用的下一個命令所需的登錄憑據,請訪問您的 OpenShift 控制台。在右上角,單擊您的用戶名。將出現一個下拉菜單。單擊複製登錄命令(圖 2),這會將您轉到另一個頁面。然後單擊顯示令牌以顯示用戶名、密碼和服務器憑據以使用 Nodeshift 登錄。

在控制台中您的姓名下,您可以獲得登錄憑據。

圖 2:在控制台中您的姓名下,您可以獲得登錄憑據。

使用這些憑據,您現在可以使用 Nodeshift 登錄到您的 OpenShift 集群:

$ nodeshift login --username=developer --password=password --server=https://api.server

通過以下命令使用 Nodeshift 部署 Node.js 應用程序,將命名空間名稱替換為您的特定項目名稱:

$ nodeshift --namespace.name=<selected-project>

您的應用程序應該已部署並在 Topology 視圖中可見,如圖 3 所示。

Node.js 應用程序出現在拓撲視圖中。

圖 3:Node.js 應用程序出現在 Topology 視圖中。

在 Node.js 應用程序和 MongoDB 數據庫之間建立連接

本系列的最後一步是在 Node.js 應用程序和 MongoDB 數據庫之間建立連接,我們將在本節中完成。

服務綁定算子

此時,拓撲視圖中應顯示兩個實例:Node.js 應用程序和與 Atlas 中的 MongoDB 實例的連接(圖 4)。

拓撲視圖顯示 Node.js 應用程序和外部 MongoDB 數據庫。

圖 4:拓撲視圖顯示 Node.js 應用程序和外部 MongoDB 數據庫。

要在這些實例之間建立連接,您將使用 Service Binding Operator 來共享憑證,並使用 kube-service-bindings 來解析這些憑證(綁定數據)。

您可以通過兩種不同的方式創建服務綁定:

  • 在兩個支持服務(Node.js 應用程序和 MongoDB)之間的拓撲視圖中拖動一條線。
  • 應用指定服務綁定的 YAML 文件。

我們將使用第一個選項,在我們的例子中它更快更容易。

將鼠標懸停在 Topology 視圖中的 Node.js 應用程序上。應該會出現一個箭頭。將箭頭從 Node.js 應用程序拖到 MongoDB 實例周圍的圓圈中。應該可以看到一個工具提示,上面寫著Create service binding。釋放鼠標按鈕,一個彈出框將讓您指定服務綁定的名稱。單擊創建綁定。Node.js 應用程序的容器將立即重新啟動(圖 5)。

通過單擊拓撲視圖中的 Node.js 應用程序容器檢查 Node.js 應用程序的環境。在右側邊欄中,單擊資源→查看日誌(Pods 部分)並訪問環境選項卡。應設置環境變量,SERVICE_BINDING_ROOT如圖 6 所示。

到服務綁定

最後一步是讀取SERVICE_BINDING_ROOT變量所指示的目錄下的綁定數據,並將數據傳遞給MongoDB客戶端,建立與MongoDB數據庫的連接。您的 Node.js 應用程序已經將 kube-service-bindings 作為依賴項。因此,調用該getBinding()函數,如以下 JavaScript 代碼片段所示,完成了解析、清理和將綁定數據轉換為 MongoDB 客戶端可使用格式的所有艱苦工作:

const { MongoClient } = require("mongodb");

const serviceBindings = require("kube-service-bindings");

const { url, connectionOptions } = serviceBindings.getBinding("MONGODB", "mongodb");

const mongoClient = new MongoClient(url, connectionOptions);

而已。通過訪問 Node.js 應用程序的 URL(單擊節點上的箭頭框圖標),您可以通過 UI 對數據庫執行簡單的 CRUD 操作。

更容易與 Kubernetes 上的服務集成

在過去的一年裡,我們的團隊一直在積極開發 kube-service-bindings,讓在管理容器化應用程序方面經驗很少或沒有經驗的開發人員更容易在支持服務之間安全地共享憑證。

作為對kube-service-bindings 開發工作的補充,我們的團隊提供了 kube-service-bindings 支持的大多數客戶端的示例,使用 kube-service-bindings 的說明,以及如何通過以下方式部署各種後端服務的描述Kubernetes 和 OpenShift 環境中的 Nodeshift。

本系列文章展示了支持哪些客戶端以及服務綁定和 kube-service-bindings 是如何工作的。我們指導您完成了使用 SBO 和 kube-service-bindings 部署 Node.js 應用程序支持服務、共享和解析 Node.js 應用程序和 MongoDB 數據庫之間連接的憑據的整個週期。kube-service-bindings 讀取、解析和轉換 Service Binding Operator 投射的綁定數據,以 MongoDB 客戶端可直接使用的形式返回數據。

為了幫助您在其他類型的部署中使用 kube-service-bindings,我們提供了額外的Node.js 示例。我們希望您發現這篇文章很有趣,並且現在對 kube-service-bindings 和服務綁定有了更好的理解。

鏈接:https ://developers.redhat.com/articles/2022/08/16/connect-mongodb-nodejs-application-kube-service-bindings#deploy_mongodb_as_a_cloud_hosted_database

#node #nodejs #mongodb #database #kubernetes

如何將 MongoDB 連接到 Kubernetes 中的 Node.js 應用程序

Как подключить MongoDB к приложению Node.js в Kubernetes

В этом кратком руководстве мы расскажем, как шаг за шагом подключить MongoDB к приложению Node.js в Kubernetes.

Разверните MongoDB как облачную базу данных

В предыдущей статье мы настроили доступ между MongoDB Atlas и вашим кластером OpenShift. Если вы успешно выполнили эти шаги, вы готовы развернуть размещенную в облаке базу данных MongoDB в кластере следующим образом:

  1. В консоли OpenShift перейдите в представление «Топология», выбрав « Разработчик» → «Топология » на левой боковой панели.
  2. Выберите проект, в котором вы хотите развернуть облачную базу данных, выбрав в верхней части левой боковой панели DeveloperTopologyProject . В раскрывающемся меню выберите свой проект.
  3. В меню левой боковой панели нажмите « +Добавить» → «Облачная база данных» → «Служба облачной базы данных MongoDB Atlas» → «Добавить в топологию» . Выберите экземпляр базы данных и нажмите « Добавить в топологию» → «Продолжить» .
  4. После успешного подключения вы попадаете в представление топологии, где размещенная в облаке база данных развернута и видна (рис. 1).

Представление «Топология» показывает, что MongoDB Atlas теперь доступен в вашем кластере.

Рис. 1. Представление «Топология» показывает, что MongoDB Atlas теперь доступен в вашем кластере.

Разверните приложение Node.js в OpenShift

Существует несколько способов развертывания приложения Node.js в OpenShift: через ocинтерфейс командной строки (CLI) OpenShift, odoCLI, консоль OpenShift и т. д. В этой статье рассматриваются два варианта: консоль OpenShift и Nodeshift , пакет NPM.

Развертывание через консоль OpenShift

С точки зрения разработчика выберите +Добавить→Импортировать из Git .

В поле URL-адрес репозитория Git задайте для URL-адреса репозитория значение https://github.com/nodeshift-blog-examples/kube-service-bindings-examples. Это репозиторий примеров привязки kube-service-bindings, поддерживаемый нашей командой; он содержит приложение Node.js, которое вы развертываете в этой статье.

Разверните Показать дополнительные параметры Git . В поле Context dir задайте значение src/mongodb, которое является путем к подкаталогу, в котором находится ваше приложение Node.js.

В образе Builder выберите Node.js и нажмите « Создать » .

Развертывание через Nodeshift

Откройте терминал и клонируйте репозиторий git:

git clone https://github.com/nodeshift-blog-examples/kube-service-bindings-examples.git
$ cd ./kube-service-bindings-examples/src/mongodb

Установите Nodeshift глобально:

$ npm install -g nodeshift

Чтобы найти учетные данные для входа в систему, необходимые для следующей команды, которую вы будете использовать, посетите консоль OpenShift. В правом верхнем углу нажмите на свое имя пользователя. Появится раскрывающийся список. Нажмите команду «Копировать логин » (рис. 2), которая перенесет вас на другую страницу. Затем нажмите « Показать токен », чтобы отобразить имя пользователя, пароль и учетные данные сервера для входа в систему с помощью Nodeshift.

Под своим именем в консоли вы можете получить учетные данные для входа.

Рисунок 2: Под своим именем в консоли вы можете получить учетные данные для входа.

Используя эти учетные данные, теперь вы можете войти в свой кластер OpenShift с помощью Nodeshift:

$ nodeshift login --username=developer --password=password --server=https://api.server

Разверните приложение Node.js с помощью Nodeshift с помощью следующей команды, заменив имя пространства имен на ваше конкретное имя проекта:

$ nodeshift --namespace.name=<selected-project>

Ваше приложение должно быть развернуто и отображаться в представлении «Топология», как показано на рис. 3.

Приложение Node.js появится в представлении «Топология».

Рис. 3. Приложение Node.js отображается в представлении «Топология».

Установите соединение между приложением Node.js и базой данных MongoDB.

Последний шаг в этой серии — установить соединение между вашим приложением Node.js и базой данных MongoDB, что мы и сделаем в этом разделе.

Оператор привязки службы

На этом этапе в представлении «Топология» должны появиться два экземпляра: приложение Node.js и подключение к вашему экземпляру MongoDB в Atlas (рис. 4).

В представлении «Топология» отображается как приложение Node.js, так и внешняя база данных MongoDB.

Рис. 4. В представлении «Топология» показано как приложение Node.js, так и внешняя база данных MongoDB.

Чтобы установить соединение между этими экземплярами, вы будете использовать Service Binding Operator для совместного использования учетных данных и kube-service-bindings для анализа этих учетных данных (данных привязки).

Вы можете создать привязку службы двумя способами:

  • Перетащите линию в представлении «Топология» между двумя вспомогательными службами (приложением Node.js и MongoDB).
  • Примените файл YAML, указав привязку службы.

Мы пойдем по первому варианту, который в нашем случае быстрее и проще.

Наведите указатель мыши на приложение Node.js в представлении «Топология». Должна появиться стрелка. Перетащите стрелку с приложения Node.js на кружок вокруг экземпляра MongoDB. Должна быть видна всплывающая подсказка с надписью « Создать привязку службы» . Отпустите кнопку мыши, и всплывающее окно позволит вам указать имя привязки службы. Щелкните Создать привязку . Контейнер приложения Node.js немедленно перезапустится (рис. 5).

Проверьте среду приложения Node.js, щелкнув контейнер приложения Node.js в представлении «Топология». На правой боковой панели нажмите « Ресурсы» → «Просмотреть журналы» (раздел «Модули») и перейдите на вкладку « Среда ». Переменная SERVICE_BINDING_ROOTсреды должна быть установлена, как показано на рисунке 6.

к сервис-привязкам

Последним шагом является чтение данных привязки в каталоге, указанном SERVICE_BINDING_ROOTпеременной, и передача данных клиенту MongoDB для установления соединения с базой данных MongoDB. В вашем приложении Node.js уже есть привязки kube-service-bindings в качестве зависимости. Таким образом, вызов getBinding()функции, как показано в следующем фрагменте кода JavaScript, выполняет всю тяжелую работу по разбору, очистке и преобразованию данных привязки в формат, пригодный для использования клиентом MongoDB:

const { MongoClient } = require("mongodb");

const serviceBindings = require("kube-service-bindings");

const { url, connectionOptions } = serviceBindings.getBinding("MONGODB", "mongodb");

const mongoClient = new MongoClient(url, connectionOptions);

Вот и все. Посетив URL-адрес приложения Node.js (щелкните значок со стрелкой на узле), вы можете выполнять простые операции CRUD через пользовательский интерфейс в базе данных.

Упрощенная интеграция с сервисами в Kubernetes.

В течение последнего года наша команда активно занималась разработкой привязок kube-service-bindings, что упрощает разработчикам с небольшим или нулевым опытом управления контейнерными приложениями безопасный обмен учетными данными между вспомогательными службами.

В дополнение к работе по разработке kube-service-bindings наша команда предоставляет примеры для большинства клиентов, поддерживаемых kube-service-bindings, инструкции по использованию kube-service-bindings и описание того, как развертывать различные вспомогательные сервисы через Nodeshift в средах Kubernetes и OpenShift.

В этой серии статей показано, какие клиенты поддерживаются и как работают привязки службы и привязки kube-service-bindings. Мы провели вас через весь цикл развертывания службы поддержки приложений Node.js с использованием привязок SBO и kube-service, совместного использования и анализа учетных данных для соединения между приложением Node.js и базой данных MongoDB. kube-service-bindings считывает, анализирует и преобразует данные привязки, спроецированные оператором привязки службы, возвращая данные в форме, которую может напрямую использовать клиент MongoDB.

Чтобы помочь вам использовать привязки kube-service-bindings в других типах развертываний, мы предоставили дополнительные примеры Node.js. Мы надеемся, что вы нашли эту статью интересной и теперь лучше понимаете привязки kube-service-bindings и сервисов в целом.

Ссылка: https://developers.redhat.com/articles/2022/08/16/connect-mongodb-nodejs-application-kube-service-bindings#deploy_mongodb_as_a_cloud_hosted_database

#узел #nodejs #mongodb #база данных #kubernetes

Как подключить MongoDB к приложению Node.js в Kubernetes
Chloe  Butler

Chloe Butler

1660417440

How to Build Zomato Clone WebSite using React and MongoDB

Zomato-clone

Zomato is an Indian multinational restaurant aggregator and food delivery company founded by Deepinder Goyal and Pankaj Chaddah in 2008. Zomato provides information, menus and user-reviews of restaurants as well as food delivery options from partner restaurants in select cities. As of 2019, the service is available in 24 countries and in more than 10,000 cities.

Tech Stack used in this Project

Reactjs, MongoDB, Express , Nodejs, HTML, CSS, Bootstrap, firebase

Deployment Link

https://zomato-clone-suraj-devere.vercel.app/

Collaborators

Screenshots

Home page this is the home page of zomato.com clone.

category page

cart page


Author: pooja171195
Source code: https://github.com/pooja171195/Zomato-Clone
 

#javascript #react-native #mongodb 

How to Build Zomato Clone WebSite using React and MongoDB
Nat  Grady

Nat Grady

1660315989

Rmongodb: R Driver for MongoDB

Project status

Dear R and rmongodb users, rmongodb project is based on legacy C drivers. For the moment, I (@dselivanov) don't have time for rmongodb development. And unless someone will not port new drivers, package will remain with outdated functionality (see issues ). If some of you want to udertake package maintainance - let me know.

For new R / mongodb users , I recommend to start with mongolite package wich is much more actively maintained.

Usage

Once you have installed the package, it may be loaded from within R like any other package:

library("rmongodb")

# connect to your local mongodb
mongo <- mongo.create()

# create query object 
query <- mongo.bson.from.JSON('{"age": 27}')

# Find the first 100 records
#    in collection people of database test where age == 27
cursor <- mongo.find(mongo, "test.people", query, limit=100L)
# Step through the matching records and display them
while (mongo.cursor.next(cursor))
    print(mongo.cursor.value(cursor))
mongo.cursor.destroy(cursor)

res <- mongo.find.batch(mongo, "test.people", query, limit=100L)

mongo.disconnect(mongo)
mongo.destroy(mongo)

There is also one demo available:

library("rmongodb")
demo(teachers_aid)

Supported Functionality by rmongodb

  • Connecting and disconnecting to MongoDB
  • Querying, inserting and updating to MongoDB including with JSON and BSON
  • Creating and handling BSON objects
  • Dropping collections and databases on MongoDB
  • Creating indices on MongoDB collections
  • Error handling
  • Executing commands on MongoDB
  • Adding, removing, handling files on a "Grid File System" (GridFS) on a MongoDB server
  • High Level functionality as mongo.apply, mongo.summary, mongo.get.keys, ...
  • Aggregation pipeline

Good ressources to Get Started with rmongodb

Basic Overview of using the rmongodb package for R - December 2013, Brock Tibert
code examples: https://gist.github.com/Btibert3/7751989

R with MongoDB - MongoDB Munich conference, October 2013, Markus Schmidberger

Accessing mongodb from R - January 2012, Sean Davis
code examples: http://watson.nci.nih.gov/~sdavis/blog/rmongodb-using-R-with-mongo/

R and MongoDB - June 2013, WenSui
example comparing rmongodb and RMongo: http://www.r-bloggers.com/r-and-mongodb/

rmongodb – R Driver for MongoDB - September 2011, Gerald Lindsly
blog post: http://www.r-bloggers.com/rmongodb-r-driver-for-mongodb/

Stackoverflow questions and answers:
http://stackoverflow.com/questions/tagged/rmongodb

Good ressources to Install and Get Started with MongoDB

Installing MongoDB, MongoDB Doku
http://docs.mongodb.org/manual/installation/

Getting Started with MongoDB, MongoDB Doku
http://docs.mongodb.org/manual/tutorial/getting-started/

MongoDB - Getting Started Guide, April 2013, Satish

Little MongoDB Book

Good ressources for working with JSON-Data in R:

Development

To install the development version of rmongodb, it's easiest to use the devtools package:

# install.packages("devtools")
library(devtools)
install_github("mongosoup/rmongodb")

We advice using RStudio (www.rstudio.org) for the package development. The RStudio .Rproj file is included in the repository.

Usefull links

Versioning

We use a three step version number system, e.g. v1.2.1:

  • first: major changes as new C libraries
  • second: for each new stable CRAN release
  • third: for each new github version ready for testing

General Development Rules

  • we use roxygen2
  • we write RUnit tests for all new functionality in tests/test_XXX.R
  • for bigger changes we use branches
  • run valgrid to check for memory leaks R -d "valgrind --tool=memcheck --leak-check=full" --vanilla < test_XXX.R > log.txt 2>&1
  • CRAN submission:
  • http://cran.r-project.org/submit.html
  • create Package tar.gz via RStudio "Build Source Package"
  • run R CRAN checks via: R CMD check --as-cran package.tar.gz
  • run R CRAN checks without running mongodb installation
  • create a tag / release on github for every CRAN submission

rmongodb

This is an R (www.r-project.org) extension supporting access to MongoDB (www.mongodb.org) using the mongodb-c-driver (http://docs.mongodb.org/ecosystem/drivers/c/).

The latest stable version is available on CRAN: http://cran.r-project.org/package=rmongodb

Thanks to Gerald Lindsly and MongoDB, Inc. (formerly 10gen) for the initial work.

In October 2013, MongoSoup and Markus Schmidberger have overtaken the development and maintenance of the R package.

Since October 2014 package is maintained by Dmitriy Selivanov. Please feel free to send us issues or pull requests via github: https://github.com/mongosoup/rmongodb

Furthermore, I'm happy to get your feedback personally via email: selivanov.dmitriy (at) gmail.com.

Download Details:

Author: dselivanov
Source Code: https://github.com/dselivanov/rmongodb 

#r #driver #mongodb 

Rmongodb: R Driver for MongoDB
Nat  Grady

Nat Grady

1660300680

Mongolite: Fast and Simple MongoDB Client for R

mongolite

Fast and Simple MongoDB Client for R

High-level, high-performance MongoDB client based on libmongoc and jsonlite. Includes support for aggregation, indexing, map-reduce, streaming, SSL encryption and SASL authentication. The vignette gives a brief overview of the available methods in the package.

Documentation

About the R package:

Hello World

Example using a public test server

con <- mongo("mtcars", url =
  "mongodb+srv://readwrite:test@cluster0-84vdt.mongodb.net/test")

# Wipe collection
if(con$count() > 0) 
  con$drop()
  
# Insert some data
con$insert(mtcars)
stopifnot(con$count() == nrow(mtcars))

# Query data
mydata <- con$find()
stopifnot(all.equal(mydata, mtcars))
con$drop()

# Automatically disconnect when connection is removed
rm(con)
gc()

Insert/retrieve data from your local mongodb server:

# Init connection to local mongod
library(mongolite)
m <- mongo(collection = "diamonds")

# Insert test data
data(diamonds, package="ggplot2")
m$insert(diamonds)

# Check records
m$count()
nrow(diamonds)

# Perform a query and retrieve data
out <- m$find('{"cut" : "Premium", "price" : { "$lt" : 1000 } }')

# Compare
nrow(out)
nrow(subset(diamonds, cut == "Premium" & price < 1000))

More advanced features include map reduce:

# Cross-table
tbl <- m$mapreduce(
  map = "function(){emit({cut:this.cut, color:this.color}, 1)}",
  reduce = "function(id, counts){return Array.sum(counts)}"
)
# Same as:
data.frame(with(diamonds, table(cut, color)))

Importing and exporting json or bson data:

# Stream jsonlines into a connection
tmp <- tempfile()
m$export(file(tmp))

# Stream it back in R
library(jsonlite)
mydata <- stream_in(file(tmp))

# Or into mongo
m2 <- mongo("diamonds2")
m2$count()
m2$import(file(tmp))
m2$count()

# Remove the collection
m$drop()
m2$drop()

Installation

Binary packages for OS-X or Windows can be installed directly from CRAN:

install.packages("mongolite")

Installation from source on Linux requires openssl and Cyrus SASL (not GNU sasl). On Debian or Ubuntu use libssl-dev and libsasl2-dev:

sudo apt-get install -y libssl-dev libsasl2-dev

On Fedora, CentOS or RHEL use openssl-devel and cyrus-sasl-devel:

sudo yum install openssl-devel cyrus-sasl-devel

Download Details:

Author: jeroen
Source Code: https://github.com/jeroen/mongolite 

#r #mongodb #client  

Mongolite: Fast and Simple MongoDB Client for R

How to Develop an Asynchronous API with FastAPI and MongoDB

In this tutorial, you'll learn how to develop an asynchronous API with FastAPI and MongoDB. We'll be using the Motor package to interact with MongoDB asynchronously.

Source: https://testdriven.io

#crud #fastapi #mongodb #heroku 

How to Develop an Asynchronous API with FastAPI and MongoDB
Thai  Son

Thai Son

1660204560

Cách Phát Triển Một API Không Đồng Bộ Với FastAPI Và MongoDB

Trong hướng dẫn này, bạn sẽ học cách phát triển một API không đồng bộ với FastAPIMongoDB . Chúng tôi sẽ sử dụng gói Motor để tương tác không đồng bộ với MongoDB.

Mục tiêu

Đến cuối hướng dẫn này, bạn sẽ có thể:

  1. Phát triển một API RESTful với Python và FastAPI
  2. Tương tác không đồng bộ với MongoDB
  3. Chạy MongoDB trên đám mây với MongoDB Atlas
  4. Triển khai ứng dụng FastAPI cho Heroku

Thiết lập ban đầu

Bắt đầu bằng cách tạo một thư mục mới để chứa dự án của bạn có tên "fastapi-mongo":

$ mkdir fastapi-mongo
$ cd fastapi-mongo

Tiếp theo, tạo và kích hoạt một môi trường ảo:

$ python3.9 -m venv venv
$ source venv/bin/activate
$ export PYTHONPATH=$PWD

Hãy trao đổi virtualenv và Pip cho thơ hoặc Pipenv . Để biết thêm, hãy xem lại Môi trường Python hiện đại .

Tiếp theo, tạo các tệp và thư mục sau:

├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       └── routes
└── requirements.txt

Thêm các phần phụ thuộc sau vào tệp tin request.txt của bạn :

fastapi==0.73.0
uvicorn==0.17.4

Cài đặt chúng:

(venv)$ pip install -r requirements.txt

Trong tệp app / main.py , xác định một điểm vào để chạy ứng dụng:

import uvicorn

if __name__ == "__main__":
    uvicorn.run("server.app:app", host="0.0.0.0", port=8000, reload=True)

Ở đây, chúng tôi đã hướng dẫn tệp chạy máy chủ Uvicorn trên cổng 8000 và tải lại sau mỗi lần thay đổi tệp.

Trước khi khởi động máy chủ thông qua tệp điểm nhập, hãy tạo một tuyến cơ sở trong app / server / app.py :

from fastapi import FastAPI

app = FastAPI()


@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to this fantastic app!"}

Thẻ là số nhận dạng được sử dụng để nhóm các tuyến đường. Các tuyến có cùng thẻ được nhóm thành một phần trên tài liệu API.

Run the entry point file from your console:

(venv)$ python app/main.py

Navigate to http://localhost:8000 in your browser. You should see:

{
  "message": "Welcome to this fantastic app!"
}

You can also view the interactive API documentation at http://localhost:8000/docs:

fastapi swagger ui

Routes

We'll be building a simple app for storing student data with the following CRUD routes:

các tuyến đường thô sơ

Before we dive into writing the routes, let's first define the relevant schema and configure MongoDB.

Schema

Let's define the Schema for which our data will be based on, which will represent how data is stored in the MongoDB database.

Pydantic Schema's are used for validating data along with serializing (JSON -> Python) and de-serializing (Python -> JSON). It does not serve as a Mongo schema validator, in other words.

In the "app/server/models" folder, create a new file called student.py:

from typing import Optional

from pydantic import BaseModel, EmailStr, Field


class StudentSchema(BaseModel):
    fullname: str = Field(...)
    email: EmailStr = Field(...)
    course_of_study: str = Field(...)
    year: int = Field(..., gt=0, lt=9)
    gpa: float = Field(..., le=4.0)

    class Config:
        schema_extra = {
            "example": {
                "fullname": "John Doe",
                "email": "jdoe@x.edu.ng",
                "course_of_study": "Water resources engineering",
                "year": 2,
                "gpa": "3.0",
            }
        }


class UpdateStudentModel(BaseModel):
    fullname: Optional[str]
    email: Optional[EmailStr]
    course_of_study: Optional[str]
    year: Optional[int]
    gpa: Optional[float]

    class Config:
        schema_extra = {
            "example": {
                "fullname": "John Doe",
                "email": "jdoe@x.edu.ng",
                "course_of_study": "Water resources and environmental engineering",
                "year": 4,
                "gpa": "4.0",
            }
        }


def ResponseModel(data, message):
    return {
        "data": [data],
        "code": 200,
        "message": message,
    }


def ErrorResponseModel(error, code, message):
    return {"error": error, "code": code, "message": message}

In the code above, we defined a Pydantic Schema called StudentSchema that represents how the student data will be stored in your MongoDB database.

In Pydantic, the ellipsis, ..., indicates that a Field is required. It could be replaced with None or a default value. In StudentSchema, each field has an ellipsis, since each field is important and the program shouldn't proceed without having the values set.

In the gpa and year field in the StudentSchema, we added the validators gt, lt, and le:

  1. gt and lt in the year field ensures that the value passed is greater than 0 and less than 9. As a result, values such as 0, 10, 11, will result in errors.
  2. le validator in the gpa field ensures that the value passed is less than or equal to 4.0.

This schema will help users send HTTP requests with the proper shape to the API -- i.e., the type of data to send and how to send it.

FastAPI uses Pyantic Schemas to automatically document data models in conjunction with Json Schema. Swagger UI then renders the data from the generated data models. You can read more about how FastAPI generates API documentation here.

Since we used EmailStr, we need to install email-validator.

Add it to the requirements file:

pydantic[email]

Install:

(venv)$ pip install -r requirements.txt

With the schema in place, let's set up MongoDB before writing the routes for the API.

MongoDB

In this section, we'll wire up MongoDB and configure our application to communicate with it.

According to Wikipedia, MongoDB is a cross-platform document-oriented database program. Classified as a NoSQL database program, MongoDB uses JSON-like documents with optional schemas.

MongoDB Setup

If you don't have MongoDB installed on your machine, refer to the Installation guide from the docs. Once installed, continue with the guide to run the mongod daemon process. Once done, you can verify that MongoDB is up and running, by connecting to the instance via the mongo shell command:

$ mongo

For reference, this tutorial uses MongoDB Community Edition v5.0.6.

$ mongo --version

MongoDB shell version v5.0.6

Build Info: {
    "version": "5.0.6",
    "gitVersion": "212a8dbb47f07427dae194a9c75baec1d81d9259",
    "modules": [],
    "allocator": "system",
    "environment": {
        "distarch": "x86_64",
        "target_arch": "x86_64"
    }
}

Motor Setup

Next, we'll configure Motor, an asynchronous MongoDB driver, to interact with the database.

Start by adding the dependency to the requirements file:

motor==2.5.1

Install:

(venv)$ pip install -r requirements.txt

Back in the app, add the database connection info to app/server/database.py:

import motor.motor_asyncio

MONGO_DETAILS = "mongodb://localhost:27017"

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)

database = client.students

student_collection = database.get_collection("students_collection")

In the code above, we imported Motor, defined the connection details, and created a client via AsyncIOMotorClient.

We then referenced a database called students and a collection (akin to a table in a relational database) called students_collection. Since these are just references and not actual I/O, neither requires an await expression. When the first I/O operation is made, both the database and collection will be created if they don't already exist.

Next, create a quick helper function for parsing the results from a database query into a Python dict.

Add this to the database.py file as well:

import motor.motor_asyncio

MONGO_DETAILS = "mongodb://localhost:27017"

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)

database = client.students

student_collection = database.get_collection("students_collection")


# helpers


def student_helper(student) -> dict:
    return {
        "id": str(student["_id"]),
        "fullname": student["fullname"],
        "email": student["email"],
        "course_of_study": student["course_of_study"],
        "year": student["year"],
        "GPA": student["gpa"],
    }

Next, let's write the CRUD database operations.

Database CRUD Operations

Start by importing the ObjectId method from the bson package at the top of the database.py file:

from bson.objectid import ObjectId

bson comes installed as a dependency of motor.

Next, add each of the following functions for the CRUD operations:

# Retrieve all students present in the database
async def retrieve_students():
    students = []
    async for student in student_collection.find():
        students.append(student_helper(student))
    return students


# Add a new student into to the database
async def add_student(student_data: dict) -> dict:
    student = await student_collection.insert_one(student_data)
    new_student = await student_collection.find_one({"_id": student.inserted_id})
    return student_helper(new_student)


# Retrieve a student with a matching ID
async def retrieve_student(id: str) -> dict:
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        return student_helper(student)


# Update a student with a matching ID
async def update_student(id: str, data: dict):
    # Return false if an empty request body is sent.
    if len(data) < 1:
        return False
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        updated_student = await student_collection.update_one(
            {"_id": ObjectId(id)}, {"$set": data}
        )
        if updated_student:
            return True
        return False


# Delete a student from the database
async def delete_student(id: str):
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        await student_collection.delete_one({"_id": ObjectId(id)})
        return True

In the code above, we defined the asynchronous operations to create, read, update, and delete student data in the database via motor.

In the update and delete operations, the student is searched for in the database to decide whether to carry out the operation or not. The return values guide how to send responses to the user which we'll be working on in the next section.

CRUD Routes

In this section, we'll add the routes to complement the database operations in the database file.

In the "routes" folder, create a new file called student.py and add the following content to it:

from fastapi import APIRouter, Body
from fastapi.encoders import jsonable_encoder

from app.server.database import (
    add_student,
    delete_student,
    retrieve_student,
    retrieve_students,
    update_student,
)
from app.server.models.student import (
    ErrorResponseModel,
    ResponseModel,
    StudentSchema,
    UpdateStudentModel,
)

router = APIRouter()

We'll be using the JSON Compatible Encoder from FastAPI to convert our models into a format that's JSON compatible.

Next, wire up the student route in app/server/app.py:

from fastapi import FastAPI

from app.server.routes.student import router as StudentRouter

app = FastAPI()

app.include_router(StudentRouter, tags=["Student"], prefix="/student")


@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to this fantastic app!"}

Create

Back in the routes file, add the following handler for creating a new student:

@router.post("/", response_description="Student data added into the database")
async def add_student_data(student: StudentSchema = Body(...)):
    student = jsonable_encoder(student)
    new_student = await add_student(student)
    return ResponseModel(new_student, "Student added successfully.")

So, the route expects a payload that matches the format of StudentSchema. Example:

{
    "fullname": "John Doe",
    "email": "jdoe@x.edu.ng",
    "course_of_study": "Water resources engineering",
    "year": 2,
    "gpa": "3.0",
}

Fire up the Uvicorn server:

(venv)$ python app/main.py

And refresh the interactive API documentation page at http://localhost:8000/docs to view the new route:

vênh váo ui

Test it out as well:

vênh váo ui

Vì vậy, khi một yêu cầu được gửi đến điểm cuối, nó sẽ lưu trữ phần thân yêu cầu được mã hóa JSON trong biến studenttrước khi gọi add_studentphương thức cơ sở dữ liệu và lưu trữ phản hồi trong new_studentbiến. Phản hồi từ cơ sở dữ liệu sau đó được trả về thông qua ResponseModel.

Kiểm tra các trình xác thực cũng như:

  1. Năm phải lớn hơn 0 và nhỏ hơn 10
  2. Điểm trung bình phải nhỏ hơn hoặc bằng 4,0

vênh váo ui

Đọc

Di chuyển sang phải, thêm các tuyến đường sau để truy xuất tất cả học sinh và một học sinh:

@router.get("/", response_description="Students retrieved")
async def get_students():
    students = await retrieve_students()
    if students:
        return ResponseModel(students, "Students data retrieved successfully")
    return ResponseModel(students, "Empty list returned")


@router.get("/{id}", response_description="Student data retrieved")
async def get_student_data(id):
    student = await retrieve_student(id)
    if student:
        return ResponseModel(student, "Student data retrieved successfully")
    return ErrorResponseModel("An error occurred.", 404, "Student doesn't exist.")

vênh váo ui

Điều gì xảy ra nếu bạn không chuyển một ObjectId hợp lệ - ví dụ, 1- cho ID để truy xuất một tuyến sinh viên duy nhất? Làm thế nào bạn có thể xử lý điều này tốt hơn trong ứng dụng?

Khi thao tác xóa được triển khai, bạn sẽ có cơ hội kiểm tra phản hồi cho cơ sở dữ liệu trống.

Cập nhật

Next, write the individual route for updating the student data:

@router.put("/{id}")
async def update_student_data(id: str, req: UpdateStudentModel = Body(...)):
    req = {k: v for k, v in req.dict().items() if v is not None}
    updated_student = await update_student(id, req)
    if updated_student:
        return ResponseModel(
            "Student with ID: {} name update is successful".format(id),
            "Student name updated successfully",
        )
    return ErrorResponseModel(
        "An error occurred",
        404,
        "There was an error updating the student data.",
    )

vênh váo ui

Delete

Finally, add the delete route:

@router.delete("/{id}", response_description="Student data deleted from the database")
async def delete_student_data(id: str):
    deleted_student = await delete_student(id)
    if deleted_student:
        return ResponseModel(
            "Student with ID: {} removed".format(id), "Student deleted successfully"
        )
    return ErrorResponseModel(
        "An error occurred", 404, "Student with id {0} doesn't exist".format(id)
    )

Retrieve the ID of the user you created earlier and test the delete route:

vênh váo ui

Remove any remaining students and test out the read routes again, ensuring the responses are appropriate for an empty database.

Deployment

In this section, we'll deploy the app to Heroku and configure a cloud database for MongoDB.

MongoDB Atlas

Before deploying, we need to set up MongoDB Atlas, a cloud database service for MongoDB to host our database.

Follow the Getting Started guide where you'll create an account, deploy a free tier cluster, set up a user, and whitelist an IP address.

Đối với mục đích thử nghiệm, hãy sử dụng 0.0.0.0/0IP trong danh sách trắng để cho phép truy cập từ mọi nơi. Đối với một ứng dụng sản xuất, bạn sẽ muốn hạn chế quyền truy cập vào một IP tĩnh.

Sau khi hoàn tất, lấy thông tin kết nối cơ sở dữ liệu từ cụm của bạn bằng cách nhấp vào nút "Kết nối":

tập bản đồ mongodb

Nhấp vào tùy chọn thứ hai, "Kết nối với ứng dụng của bạn":

tập bản đồ mongodb

Sao chép URL kết nối, đảm bảo cập nhật mật khẩu. Đặt cơ sở dữ liệu mặc định thành "sinh viên". Nó sẽ trông tương tự như:

mongodb+srv://foobar:foobar@cluster0.0reol.mongodb.net/students?retryWrites=true&w=majority

Thay vì mã hóa cứng giá trị này trong ứng dụng của chúng tôi, chúng tôi sẽ xác định nó có một biến môi trường. Tạo một tệp mới có tên .env trong thư mục gốc của dự án và thông tin kết nối với tệp đó:

MONGO_DETAILS=your_connection_url

Đảm bảo thay thế your_connection_urlbằng URL đã sao chép.

Tiếp theo, để đơn giản hóa việc quản lý các biến môi trường trong ứng dụng của chúng tôi, hãy cài đặt gói Python Decouple . Thêm nó vào tệp yêu cầu của bạn như sau:

python-decouple==3.6

Cài đặt:

(venv)$ pip install -r requirements.txt

Trong tệp app / server / database.py , hãy nhập thư viện:

from decouple import config

Phương thức đã nhập configsẽ quét qua thư mục gốc để tìm tệp .env và đọc nội dung được chuyển đến nó. Vì vậy, trong trường hợp của chúng ta, nó sẽ đọc MONGO_DETAILSbiến.

Tiếp theo, thay đổi MONGO_DETAILSbiến thành:

MONGO_DETAILS = config("MONGO_DETAILS")  # read environment variable

Kiểm tra cục bộ

Trước khi triển khai, hãy kiểm tra ứng dụng cục bộ với cơ sở dữ liệu đám mây để đảm bảo rằng kết nối được định cấu hình đúng. Khởi động lại máy chủ Uvicorn của bạn và kiểm tra từng tuyến đường từ tài liệu tương tác tại http: // localhost: 8000 / docs .

Bạn sẽ có thể xem dữ liệu trên trang tổng quan Atlas:

tập bản đồ mongodb

Triển khai đến Heroku

Cuối cùng, hãy triển khai ứng dụng cho Heroku .

Heroku là một Nền tảng đám mây dưới dạng Dịch vụ (PaaS) được sử dụng để triển khai và mở rộng các ứng dụng.

Nếu cần, hãy đăng ký tài khoản Heroku và cài đặt Heroku CLI .

Trước khi tiếp tục, hãy tạo tệp .gitignore trong dự án để ngăn chặn việc kiểm tra trong thư mục "venv" và tệp .env thành git:

(venv)$ touch .gitignore

Thêm những điều sau:

.env
venv/
__pycache__

Tiếp theo, thêm một Procfile vào thư mục gốc của dự án của bạn:

web: uvicorn app.server.app:app --host 0.0.0.0 --port=$PORT

Ghi chú:

  1. Procfile là một tệp văn bản, được đặt ở thư mục gốc của dự án của bạn, hướng dẫn Heroku cách chạy ứng dụng của bạn. Vì chúng tôi đang cung cấp một ứng dụng web, chúng tôi đã xác định loại quy trình webcùng với lệnh để cung cấp Uvicorn.
  2. Heroku tự động hiển thị một cổng để ứng dụng của bạn chạy tại thời điểm triển khai, cổng này được hiển thị thông qua $PORTbiến môi trường.

Dự án của bạn bây giờ sẽ có các tệp và thư mục sau:

├── .env
├── .gitignore
├── Procfile
├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       │   └── student.py
│       └── routes
│           └── student.py
└── requirements.txt

Trong thư mục gốc của dự án của bạn, hãy khởi tạo một kho lưu trữ git mới:

(venv)$ git init
(venv)$ git add .
(venv)$ git commit -m "My fastapi and mongo application"

Bây giờ, chúng ta có thể tạo một ứng dụng mới trên Heroku:

(venv)$ heroku create

Cùng với việc tạo ứng dụng mới, lệnh này tạo một kho lưu trữ git từ xa trên Heroku để chúng tôi đẩy ứng dụng của mình lên để triển khai. Sau đó, nó tự động đặt điều này làm điều khiển từ xa trên kho lưu trữ cục bộ cho chúng tôi.

Bạn có thể xác minh rằng điều khiển từ xa đã được thiết lập bằng cách chạy git remote -v.

Ghi lại URL của ứng dụng của bạn.

Vì chúng tôi không thêm tệp .env vào git, chúng tôi cần đặt biến môi trường trong môi trường Heroku:

(venv)$ heroku config:set MONGO_DETAILS="your_mongo_connection_url"

Một lần nữa, hãy đảm bảo thay thế your_connection_urlbằng URL kết nối thực.

Đẩy mã của bạn lên Heroku và đảm bảo rằng ít nhất một phiên bản của ứng dụng đang chạy:

(venv)$ git push heroku master
(venv)$ heroku ps:scale web=1

Chạy heroku openđể mở ứng dụng của bạn trong trình duyệt mặc định của bạn.

Bạn đã triển khai thành công ứng dụng của mình cho Heroku. Kiểm tra nó ra.

Sự kết luận

Trong hướng dẫn này, bạn đã học cách tạo ứng dụng CRUD với FastAPI và MongoDB và triển khai nó cho Heroku. Thực hiện tự kiểm tra nhanh bằng cách xem lại các mục tiêu ở đầu hướng dẫn. Bạn có thể tìm thấy mã được sử dụng trong hướng dẫn này trên GitHub .

Nguồn:  https://testdriven.io

#crud #fastapi #mongodb #heroku 

Cách Phát Triển Một API Không Đồng Bộ Với FastAPI Và MongoDB

Как разработать асинхронный API с помощью FastAPI и MongoDB

В этом руководстве вы узнаете, как разработать асинхронный API с помощью FastAPI и MongoDB . Мы будем использовать пакет Motor для асинхронного взаимодействия с MongoDB.

Цели

К концу этого урока вы сможете:

  1. Разработайте RESTful API с помощью Python и FastAPI
  2. Взаимодействовать с MongoDB асинхронно
  3. Запустите MongoDB в облаке с помощью MongoDB Atlas
  4. Разверните приложение FastAPI на Heroku

Начальная настройка

Начните с создания новой папки для хранения вашего проекта под названием «fastapi-mongo»:

$ mkdir fastapi-mongo
$ cd fastapi-mongo

Далее создайте и активируйте виртуальную среду:

$ python3.9 -m venv venv
$ source venv/bin/activate
$ export PYTHONPATH=$PWD

Не стесняйтесь менять virtualenv и Pip на Poetry или Pipenv . Подробнее см. в Modern Python Environments .

Далее создайте следующие файлы и папки:

├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       └── routes
└── requirements.txt

Добавьте следующие зависимости в ваш файл requirements.txt :

fastapi==0.73.0
uvicorn==0.17.4

Установите их:

(venv)$ pip install -r requirements.txt

В файле app/main.py определите точку входа для запуска приложения:

import uvicorn

if __name__ == "__main__":
    uvicorn.run("server.app:app", host="0.0.0.0", port=8000, reload=True)

Здесь мы указали файлу запускать сервер Uvicorn на порту 8000 и перезагружать его при каждом изменении файла.

Перед запуском сервера через файл точки входа создайте базовый маршрут в app/server/app.py :

from fastapi import FastAPI

app = FastAPI()


@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to this fantastic app!"}

Теги — это идентификаторы, используемые для группировки маршрутов. Маршруты с одинаковыми тегами сгруппированы в раздел документации по API.

Запустите файл точки входа с консоли:

(venv)$ python app/main.py

Перейдите по адресу http://localhost:8000 в браузере. Тебе следует увидеть:

{
  "message": "Welcome to this fantastic app!"
}

Вы также можете просмотреть интерактивную документацию по API по адресу http://localhost:8000/docs :

пользовательский интерфейс fastapi

Маршруты

Мы создадим простое приложение для хранения данных учащихся со следующими маршрутами CRUD:

сырые маршруты

Прежде чем мы углубимся в написание маршрутов, давайте сначала определим соответствующую схему и настроим MongoDB.

Схема

Давайте определим схему , на которой будут основываться наши данные, которая будет представлять, как данные хранятся в базе данных MongoDB.

Pydantic Schema используется для проверки данных наряду с сериализацией (JSON -> Python) и десериализацией (Python -> JSON). Другими словами, он не служит валидатором схемы Mongo.

В папке «app/server/models» создайте новый файл с именем student.py :

from typing import Optional

from pydantic import BaseModel, EmailStr, Field


class StudentSchema(BaseModel):
    fullname: str = Field(...)
    email: EmailStr = Field(...)
    course_of_study: str = Field(...)
    year: int = Field(..., gt=0, lt=9)
    gpa: float = Field(..., le=4.0)

    class Config:
        schema_extra = {
            "example": {
                "fullname": "John Doe",
                "email": "jdoe@x.edu.ng",
                "course_of_study": "Water resources engineering",
                "year": 2,
                "gpa": "3.0",
            }
        }


class UpdateStudentModel(BaseModel):
    fullname: Optional[str]
    email: Optional[EmailStr]
    course_of_study: Optional[str]
    year: Optional[int]
    gpa: Optional[float]

    class Config:
        schema_extra = {
            "example": {
                "fullname": "John Doe",
                "email": "jdoe@x.edu.ng",
                "course_of_study": "Water resources and environmental engineering",
                "year": 4,
                "gpa": "4.0",
            }
        }


def ResponseModel(data, message):
    return {
        "data": [data],
        "code": 200,
        "message": message,
    }


def ErrorResponseModel(error, code, message):
    return {"error": error, "code": code, "message": message}

В приведенном выше коде мы определили схему Pydantic , которая StudentSchemaпредставляет, как данные учащихся будут храниться в вашей базе данных MongoDB.

В Pydantic многоточие указывает на то , ...что требуется поле. Его можно заменить на Noneили значение по умолчанию. В StudentSchema, каждое поле имеет многоточие, так как каждое поле важно, и программа не должна продолжать работу, не установив значения.

В поле gpaand yearв StudentSchema, мы добавили валидаторы gt , ltи le:

  1. gtи ltв yearполе гарантирует, что переданное значение больше 0 и меньше 9 . В результате такие значения, как 0 , 10 , 11 , приведут к ошибкам.
  2. leвалидатор в gpaполе гарантирует, что переданное значение меньше или равно 4.0 .

Эта схема поможет пользователям отправлять HTTP-запросы с правильной формой к API, т. е. с типом данных для отправки и способом их отправки.

FastAPI использует Pyantic Schemas для автоматического документирования моделей данных в сочетании с Json Schema . Затем пользовательский интерфейс Swagger отображает данные из сгенерированных моделей данных. Подробнее о том, как FastAPI генерирует документацию по API, можно прочитать здесь .

Так как мы использовали EmailStr, нам нужно установить email-validator .

Добавьте его в файл требований:

pydantic[email]

Установить:

(venv)$ pip install -r requirements.txt

Имея схему, давайте настроим MongoDB, прежде чем писать маршруты для API.

MongoDB

В этом разделе мы подключим MongoDB и настроим наше приложение для взаимодействия с ним.

Согласно Википедии , MongoDB — это кроссплатформенная программа для баз данных, ориентированная на работу с документами. MongoDB классифицируется как программа базы данных NoSQL и использует JSON-подобные документы с необязательными схемами.

Настройка MongoDB

Если на вашем компьютере не установлена ​​MongoDB, обратитесь к руководству по установке из документации. После установки продолжите руководство по запуску процесса демона mongod . После этого вы можете убедиться, что MongoDB запущена и работает, подключившись к экземпляру с помощью команды mongoоболочки:

$ mongo

Для справки, в этом руководстве используется MongoDB Community Edition v5.0.6.

$ mongo --version

MongoDB shell version v5.0.6

Build Info: {
    "version": "5.0.6",
    "gitVersion": "212a8dbb47f07427dae194a9c75baec1d81d9259",
    "modules": [],
    "allocator": "system",
    "environment": {
        "distarch": "x86_64",
        "target_arch": "x86_64"
    }
}

Настройка двигателя

Далее мы настроим Motor , асинхронный драйвер MongoDB, для взаимодействия с базой данных.

Начните с добавления зависимости в файл требований:

motor==2.5.1

Установить:

(venv)$ pip install -r requirements.txt

Вернувшись в приложение, добавьте информацию о подключении к базе данных в app/server/database.py :

import motor.motor_asyncio

MONGO_DETAILS = "mongodb://localhost:27017"

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)

database = client.students

student_collection = database.get_collection("students_collection")

В приведенном выше коде мы импортировали Motor, определили детали подключения и создали клиент через AsyncIOMotorClient .

Затем мы сослались на базу данных с именем studentsи коллекцию (подобную таблице в реляционной базе данных) с именем students_collection. Поскольку это просто ссылки, а не фактический ввод-вывод, ни для одного из них не требуется awaitвыражение. При выполнении первой операции ввода-вывода будут созданы и база данных, и коллекция, если они еще не существуют.

Затем создайте быструю вспомогательную функцию для анализа результатов запроса к базе данных в словарь Python.

Добавьте это также в файл database.py :

import motor.motor_asyncio

MONGO_DETAILS = "mongodb://localhost:27017"

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)

database = client.students

student_collection = database.get_collection("students_collection")


# helpers


def student_helper(student) -> dict:
    return {
        "id": str(student["_id"]),
        "fullname": student["fullname"],
        "email": student["email"],
        "course_of_study": student["course_of_study"],
        "year": student["year"],
        "GPA": student["gpa"],
    }

Далее давайте напишем операции с базой данных CRUD.

CRUD-операции базы данных

Начните с импорта ObjectIdметода из пакета bson в верхней части файла database.py :

from bson.objectid import ObjectId

bson устанавливается как зависимость от двигателя.

Затем добавьте каждую из следующих функций для операций CRUD:

# Retrieve all students present in the database
async def retrieve_students():
    students = []
    async for student in student_collection.find():
        students.append(student_helper(student))
    return students


# Add a new student into to the database
async def add_student(student_data: dict) -> dict:
    student = await student_collection.insert_one(student_data)
    new_student = await student_collection.find_one({"_id": student.inserted_id})
    return student_helper(new_student)


# Retrieve a student with a matching ID
async def retrieve_student(id: str) -> dict:
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        return student_helper(student)


# Update a student with a matching ID
async def update_student(id: str, data: dict):
    # Return false if an empty request body is sent.
    if len(data) < 1:
        return False
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        updated_student = await student_collection.update_one(
            {"_id": ObjectId(id)}, {"$set": data}
        )
        if updated_student:
            return True
        return False


# Delete a student from the database
async def delete_student(id: str):
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        await student_collection.delete_one({"_id": ObjectId(id)})
        return True

В приведенном выше коде мы определили асинхронные операции для создания, чтения, обновления и удаления данных учащихся в базе данных с помощью двигателя.

В операциях обновления и удаления учащийся ищется в базе данных, чтобы решить, выполнять операцию или нет. Возвращаемые значения указывают, как отправлять ответы пользователю, над чем мы будем работать в следующем разделе.

CRUD-маршруты

В этом разделе мы добавим маршруты, дополняющие операции базы данных в файле базы данных.

В папке «routes» создайте новый файл с именем student.py и добавьте в него следующее содержимое:

from fastapi import APIRouter, Body
from fastapi.encoders import jsonable_encoder

from app.server.database import (
    add_student,
    delete_student,
    retrieve_student,
    retrieve_students,
    update_student,
)
from app.server.models.student import (
    ErrorResponseModel,
    ResponseModel,
    StudentSchema,
    UpdateStudentModel,
)

router = APIRouter()

Мы будем использовать совместимый с JSON кодировщик от FastAPI для преобразования наших моделей в формат, совместимый с JSON.

Затем подключите студенческий маршрут в app/server/app.py :

from fastapi import FastAPI

from app.server.routes.student import router as StudentRouter

app = FastAPI()

app.include_router(StudentRouter, tags=["Student"], prefix="/student")


@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to this fantastic app!"}

Создавать

Вернувшись в файл маршрутов, добавьте следующий обработчик для создания нового ученика:

@router.post("/", response_description="Student data added into the database")
async def add_student_data(student: StudentSchema = Body(...)):
    student = jsonable_encoder(student)
    new_student = await add_student(student)
    return ResponseModel(new_student, "Student added successfully.")

Таким образом, маршрут ожидает полезную нагрузку, соответствующую формату StudentSchema. Пример:

{
    "fullname": "John Doe",
    "email": "jdoe@x.edu.ng",
    "course_of_study": "Water resources engineering",
    "year": 2,
    "gpa": "3.0",
}

Запустите сервер Uvicorn:

(venv)$ python app/main.py

И обновите интерактивную страницу документации API по адресу http://localhost:8000/docs , чтобы просмотреть новый маршрут:

развязный пользовательский интерфейс

Проверьте это также:

развязный пользовательский интерфейс

So, when a request is sent to the endpoint, it stores a JSON-encoded request body in the variable student before calling the add_student database method and storing the response in the new_student variable. The response from the database is then returned via the ResponseModel.

Test out the validators as well:

  1. Year must be greater than 0 and less than 10
  2. GPA must be less than or equal to 4.0

развязный пользовательский интерфейс

Read

Moving right along, add the following routes to retrieve all students and a single student:

@router.get("/", response_description="Students retrieved")
async def get_students():
    students = await retrieve_students()
    if students:
        return ResponseModel(students, "Students data retrieved successfully")
    return ResponseModel(students, "Empty list returned")


@router.get("/{id}", response_description="Student data retrieved")
async def get_student_data(id):
    student = await retrieve_student(id)
    if student:
        return ResponseModel(student, "Student data retrieved successfully")
    return ErrorResponseModel("An error occurred.", 404, "Student doesn't exist.")

развязный пользовательский интерфейс

What happens if you don't pass in a valid ObjectId -- e.g., 1 -- for the ID to the retrieve a single student route? How can you better handle this in the application?

When the delete operation is implemented, you'll have an opportunity to test the response for an empty database.

Update

Далее напишите индивидуальный маршрут для обновления данных о студенте:

@router.put("/{id}")
async def update_student_data(id: str, req: UpdateStudentModel = Body(...)):
    req = {k: v for k, v in req.dict().items() if v is not None}
    updated_student = await update_student(id, req)
    if updated_student:
        return ResponseModel(
            "Student with ID: {} name update is successful".format(id),
            "Student name updated successfully",
        )
    return ErrorResponseModel(
        "An error occurred",
        404,
        "There was an error updating the student data.",
    )

развязный пользовательский интерфейс

Удалить

Наконец, добавьте маршрут удаления:

@router.delete("/{id}", response_description="Student data deleted from the database")
async def delete_student_data(id: str):
    deleted_student = await delete_student(id)
    if deleted_student:
        return ResponseModel(
            "Student with ID: {} removed".format(id), "Student deleted successfully"
        )
    return ErrorResponseModel(
        "An error occurred", 404, "Student with id {0} doesn't exist".format(id)
    )

Получите идентификатор пользователя, которого вы создали ранее, и протестируйте маршрут удаления:

развязный пользовательский интерфейс

Удалите всех оставшихся студентов и снова проверьте маршруты чтения, убедившись, что ответы подходят для пустой базы данных.

Развертывание

В этом разделе мы развернем приложение на Heroku и настроим облачную базу данных для MongoDB.

Атлас MongoDB

Перед развертыванием нам нужно настроить MongoDB Atlas , службу облачной базы данных для MongoDB для размещения нашей базы данных.

Следуйте руководству по началу работы , в котором вы создадите учетную запись, развернете кластер уровня бесплатного пользования, настроите пользователя и внесете IP-адрес в белый список.

В целях тестирования используйте 0.0.0.0/0IP-адрес из белого списка, чтобы разрешить доступ из любого места. Для производственного приложения вы захотите ограничить доступ к статическому IP-адресу.

После этого получите информацию о подключении к базе данных из вашего кластера, нажав кнопку «Подключиться»:

атлас mongodb

Нажмите на второй вариант «Подключиться к вашему приложению»:

атлас mongodb

Скопируйте URL-адрес подключения, обязательно обновив пароль. Также установите для базы данных по умолчанию значение «студенты». Это будет похоже на:

mongodb+srv://foobar:foobar@cluster0.0reol.mongodb.net/students?retryWrites=true&w=majority

Вместо жесткого кодирования этого значения в нашем приложении мы определим, что оно имеет переменную среды. Создайте новый файл с именем .env в корне проекта и информацию о подключении к нему:

MONGO_DETAILS=your_connection_url

Обязательно замените your_connection_urlскопированный URL-адрес.

Next, to simplify the management of environment variables in our app, let's install the Python Decouple package. Add it to your requirements file like so:

python-decouple==3.6

Install:

(venv)$ pip install -r requirements.txt

In the app/server/database.py file, import the library:

from decouple import config

The imported config method scans through the root directory for a .env file and reads the content passed to it. So, in our case, it will read the MONGO_DETAILS variable.

Next, change the MONGO_DETAILS variable to:

MONGO_DETAILS = config("MONGO_DETAILS")  # read environment variable

Testing Locally

Before deploying, let's test the app locally with the cloud database to ensure that the connection is properly configured. Restart your Uvicorn server and test each route from the interactive documentation at http://localhost:8000/docs.

You should be able to see the data on the Atlas dashboard:

атлас mongodb

Deploying to Heroku

Finally, let's deploy the app to Heroku.

Heroku is a cloud Platform as a Service (PaaS) used for deploying and scaling applications.

If necessary, sign up for a Heroku account and install the Heroku CLI.

Before proceeding, create a .gitignore file in the project to prevent checking in the "venv" folder and .env file to git:

(venv)$ touch .gitignore

Add the following:

.env
venv/
__pycache__

Next, add a Procfile to your project's root:

web: uvicorn app.server.app:app --host 0.0.0.0 --port=$PORT

Notes:

  1. A Procfile is a text file, placed at the root of your project, that guides Heroku on how to run your application. Since we're serving a web app, we defined the process type of web along with the command to serve up Uvicorn.
  2. Heroku dynamically exposes a port for your app to run at the time of deployment, which is exposed via the $PORT environment variable.

Your project should now have the following files and folders:

├── .env
├── .gitignore
├── Procfile
├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       │   └── student.py
│       └── routes
│           └── student.py
└── requirements.txt

In your project's root, initialize a new git repository:

(venv)$ git init
(venv)$ git add .
(venv)$ git commit -m "My fastapi and mongo application"

Now, we can create a new app on Heroku:

(venv)$ heroku create

Along with creating a new app, this command creates a remote git repository on Heroku for us to push our application to for deployment. It then sets this as a remote on the local repository automatically for us.

Вы можете убедиться, что пульт установлен, запустив git remote -v.

Обратите внимание на URL вашего приложения.

Поскольку мы не добавили файл .env в git, нам нужно установить переменную среды в среде Heroku:

(venv)$ heroku config:set MONGO_DETAILS="your_mongo_connection_url"

Опять же, не забудьте заменить your_connection_urlреальный URL-адрес подключения.

Отправьте свой код в Heroku и убедитесь, что запущен хотя бы один экземпляр приложения:

(venv)$ git push heroku master
(venv)$ heroku ps:scale web=1

Запустите heroku open, чтобы открыть приложение в браузере по умолчанию.

Вы успешно развернули свое приложение в Heroku. Проверьте это.

Вывод

В этом руководстве вы узнали, как создать приложение CRUD с FastAPI и MongoDB и развернуть его в Heroku. Выполните быструю самопроверку, просмотрев цели в начале руководства. Вы можете найти код, используемый в этом руководстве, на GitHub .

Источник:  https://testdriven.io

#crud #fastapi #mongodb #heroku 

Как разработать асинхронный API с помощью FastAPI и MongoDB
工藤  晃

工藤 晃

1660190040

如何使用 FastAPI 和 MongoDB 開發異步 API

在本教程中,您將學習如何使用FastAPIMongoDB開發異步 API 。我們將使用Motor包與 MongoDB 進行異步交互。

目標

在本教程結束時,您將能夠:

  1. 使用 Python 和 FastAPI 開發 RESTful API
  2. 與 MongoDB 異步交互
  3. 使用 MongoDB Atlas 在雲中運行 MongoDB
  4. 將 FastAPI 應用程序部署到 Heroku

最初設定

首先創建一個新文件夾來保存名為“fastapi-mongo”的項目:

$ mkdir fastapi-mongo
$ cd fastapi-mongo

接下來,創建並激活一個虛擬環境:

$ python3.9 -m venv venv
$ source venv/bin/activate
$ export PYTHONPATH=$PWD

隨意將 virtualenv 和 Pip 換成PoetryPipenv。有關更多信息,請查看現代 Python 環境

接下來,創建以下文件和文件夾:

├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       └── routes
└── requirements.txt

將以下依賴項添加到您的requirements.txt文件中:

fastapi==0.73.0
uvicorn==0.17.4

安裝它們:

(venv)$ pip install -r requirements.txt

app/main.py文件中,定義一個運行應用程序的入口點:

import uvicorn

if __name__ == "__main__":
    uvicorn.run("server.app:app", host="0.0.0.0", port=8000, reload=True)

在這裡,我們指示文件在端口 8000 上運行Uvicorn服務器,並在每次文件更改時重新加載。

在通過入口點文件啟動服務器之前,在app/server/app.py中創建一個基本路由:

from fastapi import FastAPI

app = FastAPI()


@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to this fantastic app!"}

標籤是用於對路由進行分組的標識符。具有相同標籤的路由被分組到 API 文檔的一個部分中。

從控制台運行入口點文件:

(venv)$ python app/main.py

在瀏覽器中導航到http://localhost:8000 。你應該看到:

{
  "message": "Welcome to this fantastic app!"
}

您還可以在http://localhost:8000/docs查看交互式 API 文檔:

fastapi 招搖用戶界面

路線

我們將使用以下 CRUD 路由構建一個簡單的應用程序來存儲學生數據:

粗魯路線

在我們開始編寫路由之前,讓我們首先定義相關的模式並配置 MongoDB。

架構

讓我們定義我們的數據將基於的模式,它將表示數據在 MongoDB 數據庫中的存儲方式。

Pydantic Sc​​hema 用於驗證數據以及序列化(JSON -> Python)和反序列化(Python -> JSON)。換句話說,它不能用作 Mongo模式驗證器。

在“app/server/models”文件夾中,創建一個名為student.py的新文件:

from typing import Optional

from pydantic import BaseModel, EmailStr, Field


class StudentSchema(BaseModel):
    fullname: str = Field(...)
    email: EmailStr = Field(...)
    course_of_study: str = Field(...)
    year: int = Field(..., gt=0, lt=9)
    gpa: float = Field(..., le=4.0)

    class Config:
        schema_extra = {
            "example": {
                "fullname": "John Doe",
                "email": "jdoe@x.edu.ng",
                "course_of_study": "Water resources engineering",
                "year": 2,
                "gpa": "3.0",
            }
        }


class UpdateStudentModel(BaseModel):
    fullname: Optional[str]
    email: Optional[EmailStr]
    course_of_study: Optional[str]
    year: Optional[int]
    gpa: Optional[float]

    class Config:
        schema_extra = {
            "example": {
                "fullname": "John Doe",
                "email": "jdoe@x.edu.ng",
                "course_of_study": "Water resources and environmental engineering",
                "year": 4,
                "gpa": "4.0",
            }
        }


def ResponseModel(data, message):
    return {
        "data": [data],
        "code": 200,
        "message": message,
    }


def ErrorResponseModel(error, code, message):
    return {"error": error, "code": code, "message": message}

在上面的代碼中,我們定義了一個名為PydanticStudentSchema Sc​​hema ,它表示學生數據將如何存儲在您的 MongoDB 數據庫中。

在 Pydantic 中,省略號,...表示字段是必需的。它可以替換None為默認值或默認值。在StudentSchema中,每個字段都有一個省略號,因為每個字段都很重要,並且程序不應該在沒有設置值的情況下繼續進行。

在 的gpaandyear字段中StudentSchema,我們添加了驗證器 gtltle

  1. gtltyear字段中確保傳遞的值大於0且小於9。因此,諸如01011之類的值將導致錯誤。
  2. le字段中的驗證器gpa確保傳遞的值小於或等於4.0

該模式將幫助用戶向 API 發送具有適當形狀的 HTTP 請求——即要發送的數據類型以及發送方式。

FastAPI 使用 Pyantic Sc​​hemas 結合Json Schema自動記錄數據模型。Swagger UI然後呈現來自生成的數據模型的數據。您可以在此處閱讀有關 FastAPI 如何生成 API 文檔的更多信息。

由於我們使用EmailStr了 ,我們需要安裝email-validator

將其添加到需求文件中:

pydantic[email]

安裝:

(venv)$ pip install -r requirements.txt

有了架構,讓我們在為 API 編寫路由之前設置 MongoDB。

MongoDB

在本節中,我們將連接 MongoDB 並配置我們的應用程序以與其通信。

根據Wikipedia,MongoDB 是一個跨平台的面向文檔的數據庫程序。MongoDB 被歸類為 NoSQL 數據庫程序,它使用帶有可選模式的類似 JSON 的文檔。

MongoDB 設置

如果您的機器上沒有安裝 MongoDB,請參閱文檔中的安裝指南。安裝後,繼續按照指南運行mongod守護進程。mongo完成後,您可以通過shell 命令連接到實例來驗證 MongoDB 是否已啟動並運行:

$ mongo

作為參考,本教程使用 MongoDB Community Edition v5.0.6。

$ mongo --version

MongoDB shell version v5.0.6

Build Info: {
    "version": "5.0.6",
    "gitVersion": "212a8dbb47f07427dae194a9c75baec1d81d9259",
    "modules": [],
    "allocator": "system",
    "environment": {
        "distarch": "x86_64",
        "target_arch": "x86_64"
    }
}

電機設置

接下來,我們將配置異步 MongoDB 驅動程序Motor以與數據庫交互。

首先將依賴項添加到需求文件中:

motor==2.5.1

安裝:

(venv)$ pip install -r requirements.txt

回到應用程序,將數據庫連接信息添加到app/server/database.py

import motor.motor_asyncio

MONGO_DETAILS = "mongodb://localhost:27017"

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)

database = client.students

student_collection = database.get_collection("students_collection")

在上面的代碼中,我們導入了 Motor,定義了連接細節,並通過AsyncIOMotorClient創建了一個客戶端。

然後我們引用了一個名為 的數據庫students和一個名為 的集合(類似於關係數據庫中的表)students_collection。由於這些只是引用而不是實際的 I/O,因此它們都不需要await表達式。進行第一次 I/O 操作時,如果數據庫和集合不存在,則將創建它們。

接下來,創建一個快速幫助函數,用於將數據庫查詢的結果解析為 Python 字典。

將此添加到database.py文件中:

import motor.motor_asyncio

MONGO_DETAILS = "mongodb://localhost:27017"

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)

database = client.students

student_collection = database.get_collection("students_collection")


# helpers


def student_helper(student) -> dict:
    return {
        "id": str(student["_id"]),
        "fullname": student["fullname"],
        "email": student["email"],
        "course_of_study": student["course_of_study"],
        "year": student["year"],
        "GPA": student["gpa"],
    }

接下來,讓我們編寫 CRUD 數據庫操作。

數據庫 CRUD 操作

首先從database.py文件頂部的bson包中導入ObjectId方法:

from bson.objectid import ObjectId

bson 作為電機的依賴項安裝。

接下來,為 CRUD 操作添加以下每個函數:

# Retrieve all students present in the database
async def retrieve_students():
    students = []
    async for student in student_collection.find():
        students.append(student_helper(student))
    return students


# Add a new student into to the database
async def add_student(student_data: dict) -> dict:
    student = await student_collection.insert_one(student_data)
    new_student = await student_collection.find_one({"_id": student.inserted_id})
    return student_helper(new_student)


# Retrieve a student with a matching ID
async def retrieve_student(id: str) -> dict:
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        return student_helper(student)


# Update a student with a matching ID
async def update_student(id: str, data: dict):
    # Return false if an empty request body is sent.
    if len(data) < 1:
        return False
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        updated_student = await student_collection.update_one(
            {"_id": ObjectId(id)}, {"$set": data}
        )
        if updated_student:
            return True
        return False


# Delete a student from the database
async def delete_student(id: str):
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        await student_collection.delete_one({"_id": ObjectId(id)})
        return True

在上面的代碼中,我們定義了異步操作,通過motor在數據庫中創建、讀取、更新和刪除學生數據。

在更新和刪除操作中,在數據庫中搜索學生來決定是否進行操作。返回值指導如何向用戶發送響應,我們將在下一節中介紹。

CRUD 路線

在本節中,我們將添加路由以補充數據庫文件中的數據庫操作。

在“routes”文件夾中,創建一個名為student.py的新文件,並在其中添加以下內容:

from fastapi import APIRouter, Body
from fastapi.encoders import jsonable_encoder

from app.server.database import (
    add_student,
    delete_student,
    retrieve_student,
    retrieve_students,
    update_student,
)
from app.server.models.student import (
    ErrorResponseModel,
    ResponseModel,
    StudentSchema,
    UpdateStudentModel,
)

router = APIRouter()

我們將使用來自 FastAPI 的JSON Compatible Encoder將我們的模型轉換為與 JSON 兼容的格式。

接下來,在app/server/app.py中連接學生路由:

from fastapi import FastAPI

from app.server.routes.student import router as StudentRouter

app = FastAPI()

app.include_router(StudentRouter, tags=["Student"], prefix="/student")


@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to this fantastic app!"}

創造

返迴路由文件,添加以下處理程序以創建新學生:

@router.post("/", response_description="Student data added into the database")
async def add_student_data(student: StudentSchema = Body(...)):
    student = jsonable_encoder(student)
    new_student = await add_student(student)
    return ResponseModel(new_student, "Student added successfully.")

因此,該路由需要一個與StudentSchema. 例子:

{
    "fullname": "John Doe",
    "email": "jdoe@x.edu.ng",
    "course_of_study": "Water resources engineering",
    "year": 2,
    "gpa": "3.0",
}

啟動 Uvicorn 服務器:

(venv)$ python app/main.py

並在http://localhost:8000/docs刷新交互式 API 文檔頁面以查看新路由:

大搖大擺的ui

也測試一下:

大搖大擺的ui

因此,當向端點發送請求時,它會student在調用add_student數據庫方法並將響應存儲在變量中之前將 JSON 編碼的請求正文存儲在new_student變量中。來自數據庫的響應然後通過ResponseModel.

也測試驗證器:

  1. 年份必須大於 0 且小於 10
  2. GPA必須小於或等於4.0

大搖大擺的ui

繼續前進,添加以下路線以檢索所有學生和單個學生:

@router.get("/", response_description="Students retrieved")
async def get_students():
    students = await retrieve_students()
    if students:
        return ResponseModel(students, "Students data retrieved successfully")
    return ResponseModel(students, "Empty list returned")


@router.get("/{id}", response_description="Student data retrieved")
async def get_student_data(id):
    student = await retrieve_student(id)
    if student:
        return ResponseModel(student, "Student data retrieved successfully")
    return ErrorResponseModel("An error occurred.", 404, "Student doesn't exist.")

大搖大擺的ui

如果您沒有傳入有效的 ObjectId(例如,1)用於獲取單個學生路線的 ID,會發生什麼情況?如何在應用程序中更好地處理這個問題?

實現刪除操作後,您將有機會測試空數據庫的響應。

更新

Next, write the individual route for updating the student data:

@router.put("/{id}")
async def update_student_data(id: str, req: UpdateStudentModel = Body(...)):
    req = {k: v for k, v in req.dict().items() if v is not None}
    updated_student = await update_student(id, req)
    if updated_student:
        return ResponseModel(
            "Student with ID: {} name update is successful".format(id),
            "Student name updated successfully",
        )
    return ErrorResponseModel(
        "An error occurred",
        404,
        "There was an error updating the student data.",
    )

大搖大擺的ui

Delete

Finally, add the delete route:

@router.delete("/{id}", response_description="Student data deleted from the database")
async def delete_student_data(id: str):
    deleted_student = await delete_student(id)
    if deleted_student:
        return ResponseModel(
            "Student with ID: {} removed".format(id), "Student deleted successfully"
        )
    return ErrorResponseModel(
        "An error occurred", 404, "Student with id {0} doesn't exist".format(id)
    )

Retrieve the ID of the user you created earlier and test the delete route:

大搖大擺的ui

Remove any remaining students and test out the read routes again, ensuring the responses are appropriate for an empty database.

Deployment

In this section, we'll deploy the app to Heroku and configure a cloud database for MongoDB.

MongoDB Atlas

Before deploying, we need to set up MongoDB Atlas, a cloud database service for MongoDB to host our database.

Follow the Getting Started guide where you'll create an account, deploy a free tier cluster, set up a user, and whitelist an IP address.

For testing purposes, use 0.0.0.0/0 for the whitelisted IP to allow access from anywhere. For a production app you'll want to restrict access to a static IP.

Once done, grab the database connection information from your cluster by clicking the "Connect" button:

mongodb圖集

Click on the second option, "Connect to your application":

mongodb圖集

Copy the connection URL, making sure to update the password. Set the default database to "students" as well. It will look similar to:

mongodb+srv://foobar:foobar@cluster0.0reol.mongodb.net/students?retryWrites=true&w=majority

Instead of hard coding this value in our app, we'll define it has an environment variable. Create a new file called .env in the project root and the connection info to it:

MONGO_DETAILS=your_connection_url

Make sure to replace your_connection_url with the copied URL.

Next, to simplify the management of environment variables in our app, let's install the Python Decouple package. Add it to your requirements file like so:

python-decouple==3.6

Install:

(venv)$ pip install -r requirements.txt

In the app/server/database.py file, import the library:

from decouple import config

The imported config method scans through the root directory for a .env file and reads the content passed to it. So, in our case, it will read the MONGO_DETAILS variable.

Next, change the MONGO_DETAILS variable to:

MONGO_DETAILS = config("MONGO_DETAILS")  # read environment variable

Testing Locally

Before deploying, let's test the app locally with the cloud database to ensure that the connection is properly configured. Restart your Uvicorn server and test each route from the interactive documentation at http://localhost:8000/docs.

您應該能夠在 Atlas 儀表板上看到數據:

mongodb圖集

部署到 Heroku

最後,讓我們將應用程序部署到Heroku

Heroku 是一種雲平台即服務 (PaaS),用於部署和擴展應用程序。

如有必要,註冊一個 Heroku 帳戶並安裝Heroku CLI

在繼續之前,在項目中創建一個.gitignore文件,以防止將“venv”文件夾和.env文件簽入到 git:

(venv)$ touch .gitignore

添加以下內容:

.env
venv/
__pycache__

接下來,將Procfile添加到項目的根目錄:

web: uvicorn app.server.app:app --host 0.0.0.0 --port=$PORT

筆記:

  1. Procfile是一個文本文件,位於項目的根目錄,它指導 Heroku 如何運行您的應用程序。由於我們提供的是一個 Web 應用程序,我們定義了進程類型web以及提供 Uvicorn 的命令。
  2. Heroku 在部署時動態地公開一個端口供您的應用程序運行,該端口通過$PORT環境變量公開。

您的項目現在應該具有以下文件和文件夾:

├── .env
├── .gitignore
├── Procfile
├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       │   └── student.py
│       └── routes
│           └── student.py
└── requirements.txt

在項目的根目錄中,初始化一個新的 git 存儲庫:

(venv)$ git init
(venv)$ git add .
(venv)$ git commit -m "My fastapi and mongo application"

現在,我們可以在 Heroku 上創建一個新應用:

(venv)$ heroku create

除了創建一個新應用程序之外,此命令還在 Heroku 上創建一個遠程 git 存儲庫,供我們推送我們的應用程序進行部署。然後它會自動為我們將其設置為本地存儲庫上的遠程。

您可以通過運行來驗證遠程是否已設置git remote -v

記下您的應用程序的 URL。

由於我們沒有將.env文件添加到 git 中,因此我們需要在 Heroku 環境中設置環境變量:

(venv)$ heroku config:set MONGO_DETAILS="your_mongo_connection_url"

同樣,確保替換your_connection_url為真實的連接 URL。

將您的代碼推送到 Heroku 並確保至少有一個應用程序實例正在運行:

(venv)$ git push heroku master
(venv)$ heroku ps:scale web=1

運行heroku open以在默認瀏覽器中打開您的應用程序。

您已成功將應用程序部署到 Heroku。測試一下。

結論

在本教程中,您學習瞭如何使用 FastAPI 和 MongoDB 創建一個 CRUD 應用程序並將其部署到 Heroku。通過查看教程開頭的目標來執行快速自檢。您可以在GitHub上找到本教程中使用的代碼。

來源:  https ://testdriven.io

#crud #fastapi #mongodb #heroku 

如何使用 FastAPI 和 MongoDB 開發異步 API
Noelia  Graham

Noelia Graham

1660182780

Comment Développer Une API Asynchrone Avec FastAPI Et MongoDB

Dans ce tutoriel, vous apprendrez à développer une API asynchrone avec FastAPI et MongoDB . Nous utiliserons le package Motor pour interagir avec MongoDB de manière asynchrone.

Objectifs

À la fin de ce didacticiel, vous serez en mesure de :

  1. Développer une API RESTful avec Python et FastAPI
  2. Interagissez avec MongoDB de manière asynchrone
  3. Exécutez MongoDB dans le cloud avec MongoDB Atlas
  4. Déployer une application FastAPI sur Heroku

La configuration initiale

Commencez par créer un nouveau dossier pour contenir votre projet appelé "fastapi-mongo":

$ mkdir fastapi-mongo
$ cd fastapi-mongo

Ensuite, créez et activez un environnement virtuel :

$ python3.9 -m venv venv
$ source venv/bin/activate
$ export PYTHONPATH=$PWD

N'hésitez pas à échanger virtualenv et Pip contre Poetry ou Pipenv . Pour en savoir plus, consultez Environnements Python modernes .

Ensuite, créez les fichiers et dossiers suivants :

├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       └── routes
└── requirements.txt

Ajoutez les dépendances suivantes à votre fichier requirements.txt :

fastapi==0.73.0
uvicorn==0.17.4

Installez-les :

(venv)$ pip install -r requirements.txt

Dans le fichier app/main.py , définissez un point d'entrée pour exécuter l'application :

import uvicorn

if __name__ == "__main__":
    uvicorn.run("server.app:app", host="0.0.0.0", port=8000, reload=True)

Ici, nous avons demandé au fichier d'exécuter un serveur Uvicorn sur le port 8000 et de le recharger à chaque modification de fichier.

Avant de démarrer le serveur via le fichier de point d'entrée, créez une route de base dans app/server/app.py :

from fastapi import FastAPI

app = FastAPI()


@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to this fantastic app!"}

Les balises sont des identifiants utilisés pour regrouper les routes. Les routes avec les mêmes balises sont regroupées dans une section de la documentation de l'API.

Exécutez le fichier de point d'entrée depuis votre console :

(venv)$ python app/main.py

Accédez à http://localhost:8000 dans votre navigateur. Tu devrais voir:

{
  "message": "Welcome to this fantastic app!"
}

Vous pouvez également consulter la documentation interactive de l'API sur http://localhost:8000/docs :

interface utilisateur fastapi swagger

Itinéraires

Nous allons créer une application simple pour stocker les données des étudiants avec les itinéraires CRUD suivants :

routes crud

Avant de plonger dans l'écriture des routes, définissons d'abord le schéma pertinent et configurons MongoDB.

Schéma

Définissons le schéma sur lequel nos données seront basées, qui représentera la façon dont les données sont stockées dans la base de données MongoDB.

Les schémas Pydantic sont utilisés pour valider les données avec la sérialisation (JSON -> Python) et la désérialisation (Python -> JSON). En d'autres termes, il ne sert pas de validateur de schéma Mongo.

Dans le dossier "app/server/models", créez un nouveau fichier appelé student.py :

from typing import Optional

from pydantic import BaseModel, EmailStr, Field


class StudentSchema(BaseModel):
    fullname: str = Field(...)
    email: EmailStr = Field(...)
    course_of_study: str = Field(...)
    year: int = Field(..., gt=0, lt=9)
    gpa: float = Field(..., le=4.0)

    class Config:
        schema_extra = {
            "example": {
                "fullname": "John Doe",
                "email": "jdoe@x.edu.ng",
                "course_of_study": "Water resources engineering",
                "year": 2,
                "gpa": "3.0",
            }
        }


class UpdateStudentModel(BaseModel):
    fullname: Optional[str]
    email: Optional[EmailStr]
    course_of_study: Optional[str]
    year: Optional[int]
    gpa: Optional[float]

    class Config:
        schema_extra = {
            "example": {
                "fullname": "John Doe",
                "email": "jdoe@x.edu.ng",
                "course_of_study": "Water resources and environmental engineering",
                "year": 4,
                "gpa": "4.0",
            }
        }


def ResponseModel(data, message):
    return {
        "data": [data],
        "code": 200,
        "message": message,
    }


def ErrorResponseModel(error, code, message):
    return {"error": error, "code": code, "message": message}

Dans le code ci-dessus, nous avons défini un schéma Pydantic appelé StudentSchemaqui représente la manière dont les données des étudiants seront stockées dans votre base de données MongoDB.

Dans Pydantic, les points de suspension , ..., indiquent qu'un champ est requis. Il peut être remplacé par Noneou par une valeur par défaut. Dans StudentSchema, chaque champ comporte des points de suspension, car chaque champ est important et le programme ne doit pas continuer sans que les valeurs soient définies.

Dans le champ gpaet du , nous avons ajouté les validateurs , et :yearStudentSchema gtltle

  1. gtet ltdans le yearchamp assure que la valeur passée est supérieure à 0 et inférieure à 9 . Par conséquent, des valeurs telles que 0 , 10 , 11 , entraîneront des erreurs.
  2. levalidator dans le gpachamp garantit que la valeur transmise est inférieure ou égale à 4.0 .

Ce schéma aidera les utilisateurs à envoyer des requêtes HTTP avec la forme appropriée à l'API, c'est-à-dire le type de données à envoyer et comment les envoyer.

FastAPI utilise Pyantic Schemas pour documenter automatiquement les modèles de données en conjonction avec Json Schema . Swagger UI restitue ensuite les données à partir des modèles de données générés. Vous pouvez en savoir plus sur la façon dont FastAPI génère la documentation de l'API ici .

Depuis que nous avons utilisé EmailStr, nous devons installer email-validator .

Ajoutez-le au fichier requirements :

pydantic[email]

Installer:

(venv)$ pip install -r requirements.txt

Avec le schéma en place, configurons MongoDB avant d'écrire les routes pour l'API.

MongoDB

Dans cette section, nous allons câbler MongoDB et configurer notre application pour communiquer avec elle.

Selon Wikipedia , MongoDB est un programme de base de données multiplateforme orienté document. Classé comme programme de base de données NoSQL, MongoDB utilise des documents de type JSON avec des schémas facultatifs.

Configuration de MongoDB

Si MongoDB n'est pas installé sur votre machine, reportez-vous au guide d' installation de la documentation. Une fois installé, continuez avec le guide pour exécuter le processus du démon mongod . Une fois cela fait, vous pouvez vérifier que MongoDB est opérationnel en vous connectant à l'instance via la mongocommande shell :

$ mongo

Pour référence, ce tutoriel utilise MongoDB Community Edition v5.0.6.

$ mongo --version

MongoDB shell version v5.0.6

Build Info: {
    "version": "5.0.6",
    "gitVersion": "212a8dbb47f07427dae194a9c75baec1d81d9259",
    "modules": [],
    "allocator": "system",
    "environment": {
        "distarch": "x86_64",
        "target_arch": "x86_64"
    }
}

Configuration du moteur

Ensuite, nous allons configurer Motor , un pilote MongoDB asynchrone, pour interagir avec la base de données.

Commencez par ajouter la dépendance au fichier requirements :

motor==2.5.1

Installer:

(venv)$ pip install -r requirements.txt

De retour dans l'application, ajoutez les informations de connexion à la base de données à app/server/database.py :

import motor.motor_asyncio

MONGO_DETAILS = "mongodb://localhost:27017"

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)

database = client.students

student_collection = database.get_collection("students_collection")

Dans le code ci-dessus, nous avons importé Motor, défini les détails de connexion et créé un client via AsyncIOMotorClient .

Nous avons ensuite référencé une base de données appelée studentset une collection (semblable à une table dans une base de données relationnelle) appelée students_collection. Puisqu'il ne s'agit que de références et non d'E/S réelles, aucune ne nécessite d' awaitexpression. Lorsque la première opération d'E/S est effectuée, la base de données et la collection seront créées si elles n'existent pas déjà.

Ensuite, créez une fonction d'assistance rapide pour analyser les résultats d'une requête de base de données dans un dict Python.

Ajoutez ceci également au fichier database.py :

import motor.motor_asyncio

MONGO_DETAILS = "mongodb://localhost:27017"

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)

database = client.students

student_collection = database.get_collection("students_collection")


# helpers


def student_helper(student) -> dict:
    return {
        "id": str(student["_id"]),
        "fullname": student["fullname"],
        "email": student["email"],
        "course_of_study": student["course_of_study"],
        "year": student["year"],
        "GPA": student["gpa"],
    }

Ensuite, écrivons les opérations de la base de données CRUD.

Opérations CRUD de la base de données

Commencez par importer la ObjectIdméthode du package bson en haut du fichier database.py :

from bson.objectid import ObjectId

bson est installé en tant que dépendance du moteur.

Ensuite, ajoutez chacune des fonctions suivantes pour les opérations CRUD :

# Retrieve all students present in the database
async def retrieve_students():
    students = []
    async for student in student_collection.find():
        students.append(student_helper(student))
    return students


# Add a new student into to the database
async def add_student(student_data: dict) -> dict:
    student = await student_collection.insert_one(student_data)
    new_student = await student_collection.find_one({"_id": student.inserted_id})
    return student_helper(new_student)


# Retrieve a student with a matching ID
async def retrieve_student(id: str) -> dict:
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        return student_helper(student)


# Update a student with a matching ID
async def update_student(id: str, data: dict):
    # Return false if an empty request body is sent.
    if len(data) < 1:
        return False
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        updated_student = await student_collection.update_one(
            {"_id": ObjectId(id)}, {"$set": data}
        )
        if updated_student:
            return True
        return False


# Delete a student from the database
async def delete_student(id: str):
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        await student_collection.delete_one({"_id": ObjectId(id)})
        return True

Dans le code ci-dessus, nous avons défini les opérations asynchrones pour créer, lire, mettre à jour et supprimer les données des étudiants dans la base de données via motor.

Dans les opérations de mise à jour et de suppression, l'étudiant est recherché dans la base de données pour décider d'effectuer ou non l'opération. Les valeurs de retour guident la façon d'envoyer des réponses à l'utilisateur sur lesquelles nous travaillerons dans la section suivante.

Itinéraires CRUD

Dans cette section, nous ajouterons les routes pour compléter les opérations de base de données dans le fichier de base de données.

Dans le dossier "routes", créez un nouveau fichier appelé student.py et ajoutez-y le contenu suivant :

from fastapi import APIRouter, Body
from fastapi.encoders import jsonable_encoder

from app.server.database import (
    add_student,
    delete_student,
    retrieve_student,
    retrieve_students,
    update_student,
)
from app.server.models.student import (
    ErrorResponseModel,
    ResponseModel,
    StudentSchema,
    UpdateStudentModel,
)

router = APIRouter()

Nous utiliserons l' encodeur compatible JSON de FastAPI pour convertir nos modèles dans un format compatible JSON.

Ensuite, câblez la route de l'étudiant dans app/server/app.py :

from fastapi import FastAPI

from app.server.routes.student import router as StudentRouter

app = FastAPI()

app.include_router(StudentRouter, tags=["Student"], prefix="/student")


@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to this fantastic app!"}

Créer

De retour dans le fichier routes, ajoutez le gestionnaire suivant pour créer un nouvel étudiant :

@router.post("/", response_description="Student data added into the database")
async def add_student_data(student: StudentSchema = Body(...)):
    student = jsonable_encoder(student)
    new_student = await add_student(student)
    return ResponseModel(new_student, "Student added successfully.")

Ainsi, la route attend une charge utile qui correspond au format StudentSchema. Exemple:

{
    "fullname": "John Doe",
    "email": "jdoe@x.edu.ng",
    "course_of_study": "Water resources engineering",
    "year": 2,
    "gpa": "3.0",
}

Lancez le serveur Uvicorn :

(venv)$ python app/main.py

Et actualisez la page de documentation de l'API interactive à l' adresse http://localhost:8000/docs pour afficher la nouvelle route :

interface utilisateur fanfaronne

Testez-le également :

interface utilisateur fanfaronne

Ainsi, lorsqu'une demande est envoyée au point de terminaison, il stocke un corps de demande codé JSON dans la variable studentavant d'appeler la add_studentméthode de base de données et de stocker la réponse dans la new_studentvariable. La réponse de la base de données est ensuite renvoyée via le fichier ResponseModel.

Testez également les validateurs :

  1. L'année doit être supérieure à 0 et inférieure à 10
  2. GPA doit être inférieur ou égal à 4.0

interface utilisateur fanfaronne

Lis

En continuant, ajoutez les itinéraires suivants pour récupérer tous les étudiants et un seul étudiant :

@router.get("/", response_description="Students retrieved")
async def get_students():
    students = await retrieve_students()
    if students:
        return ResponseModel(students, "Students data retrieved successfully")
    return ResponseModel(students, "Empty list returned")


@router.get("/{id}", response_description="Student data retrieved")
async def get_student_data(id):
    student = await retrieve_student(id)
    if student:
        return ResponseModel(student, "Student data retrieved successfully")
    return ErrorResponseModel("An error occurred.", 404, "Student doesn't exist.")

interface utilisateur fanfaronne

Que se passe-t-il si vous ne transmettez pas un ObjectId valide -- par exemple, 1-- pour l'ID permettant de récupérer le parcours d'un seul étudiant ? Comment pouvez-vous mieux gérer cela dans l'application ?

Lorsque l'opération de suppression est implémentée, vous aurez la possibilité de tester la réponse pour une base de données vide.

Mise à jour

Ensuite, écrivez l'itinéraire individuel pour mettre à jour les données des étudiants :

@router.put("/{id}")
async def update_student_data(id: str, req: UpdateStudentModel = Body(...)):
    req = {k: v for k, v in req.dict().items() if v is not None}
    updated_student = await update_student(id, req)
    if updated_student:
        return ResponseModel(
            "Student with ID: {} name update is successful".format(id),
            "Student name updated successfully",
        )
    return ErrorResponseModel(
        "An error occurred",
        404,
        "There was an error updating the student data.",
    )

interface utilisateur fanfaronne

Effacer

Enfin, ajoutez la route de suppression :

@router.delete("/{id}", response_description="Student data deleted from the database")
async def delete_student_data(id: str):
    deleted_student = await delete_student(id)
    if deleted_student:
        return ResponseModel(
            "Student with ID: {} removed".format(id), "Student deleted successfully"
        )
    return ErrorResponseModel(
        "An error occurred", 404, "Student with id {0} doesn't exist".format(id)
    )

Récupérez l'ID de l'utilisateur que vous avez créé précédemment et testez la route de suppression :

interface utilisateur fanfaronne

Supprimez tous les étudiants restants et testez à nouveau les itinéraires de lecture, en vous assurant que les réponses sont appropriées pour une base de données vide.

Déploiement

Dans cette section, nous allons déployer l'application sur Heroku et configurer une base de données cloud pour MongoDB.

Atlas MongoDB

Avant le déploiement, nous devons configurer MongoDB Atlas , un service de base de données cloud pour MongoDB pour héberger notre base de données.

Suivez le guide de mise en route où vous allez créer un compte, déployer un cluster de niveau gratuit, configurer un utilisateur et ajouter une adresse IP à la liste blanche.

À des fins de test, utilisez 0.0.0.0/0l'adresse IP sur liste blanche pour autoriser l'accès depuis n'importe où. Pour une application de production, vous souhaiterez restreindre l'accès à une adresse IP statique.

Une fois cela fait, récupérez les informations de connexion à la base de données de votre cluster en cliquant sur le bouton "Se connecter":

atlas mongodb

Cliquez sur la deuxième option, "Se connecter à votre application":

atlas mongodb

Copiez l'URL de connexion en veillant à mettre à jour le mot de passe. Définissez également la base de données par défaut sur "étudiants". Il ressemblera à :

mongodb+srv://foobar:foobar@cluster0.0reol.mongodb.net/students?retryWrites=true&w=majority

Au lieu de coder en dur cette valeur dans notre application, nous définirons qu'elle a une variable d'environnement. Créez un nouveau fichier appelé .env à la racine du projet et les informations de connexion :

MONGO_DETAILS=your_connection_url

Assurez-vous de remplacer your_connection_urlpar l'URL copiée.

Ensuite, pour simplifier la gestion des variables d'environnement dans notre application, installons le package Python Decouple . Ajoutez-le à votre fichier d'exigences comme suit :

python-decouple==3.6

Installer:

(venv)$ pip install -r requirements.txt

Dans le fichier app/server/database.py , importez la bibliothèque :

from decouple import config

La méthode importée configparcourt le répertoire racine à la recherche d'un fichier .env et lit le contenu qui lui est transmis. Donc, dans notre cas, il lira la MONGO_DETAILSvariable.

Ensuite, changez la MONGO_DETAILSvariable en :

MONGO_DETAILS = config("MONGO_DETAILS")  # read environment variable

Tester localement

Avant de déployer, testons l'application localement avec la base de données cloud pour nous assurer que la connexion est correctement configurée. Redémarrez votre serveur Uvicorn et testez chaque route à partir de la documentation interactive sur http://localhost:8000/docs .

Vous devriez pouvoir voir les données sur le tableau de bord Atlas :

atlas mongodb

Déploiement sur Heroku

Enfin, déployons l'application sur Heroku .

Heroku est une plate-forme cloud en tant que service (PaaS) utilisée pour déployer et faire évoluer des applications.

Si nécessaire, créez un compte Heroku et installez la CLI Heroku .

Avant de continuer, créez un fichier .gitignore dans le projet pour empêcher l'archivage du dossier "venv" et du fichier .env dans git :

(venv)$ touch .gitignore

Ajoutez ce qui suit :

.env
venv/
__pycache__

Ensuite, ajoutez un Profile à la racine de votre projet :

web: uvicorn app.server.app:app --host 0.0.0.0 --port=$PORT

Remarques:

  1. Un Procfile est un fichier texte, placé à la racine de votre projet, qui guide Heroku sur la façon d'exécuter votre application. Puisque nous servons une application Web, nous avons défini le type de processus webavec la commande pour servir Uvicorn.
  2. Heroku expose dynamiquement un port pour que votre application s'exécute au moment du déploiement, qui est exposé via la $PORTvariable d'environnement.

Votre projet doit maintenant contenir les fichiers et dossiers suivants :

├── .env
├── .gitignore
├── Procfile
├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       │   └── student.py
│       └── routes
│           └── student.py
└── requirements.txt

Dans la racine de votre projet, initialisez un nouveau dépôt git :

(venv)$ git init
(venv)$ git add .
(venv)$ git commit -m "My fastapi and mongo application"

Maintenant, nous pouvons créer une nouvelle application sur Heroku :

(venv)$ heroku create

En plus de créer une nouvelle application, cette commande crée un référentiel git distant sur Heroku pour que nous poussions notre application pour le déploiement. Il définit ensuite cela comme une télécommande sur le référentiel local automatiquement pour nous.

Vous pouvez vérifier que la télécommande est définie en exécutant git remote -v.

Notez l'URL de votre application.

Comme nous n'avons pas ajouté le fichier .env à git, nous devons définir la variable d'environnement dans l'environnement Heroku :

(venv)$ heroku config:set MONGO_DETAILS="your_mongo_connection_url"

Encore une fois, assurez-vous de remplacer your_connection_urlpar la véritable URL de connexion.

Envoyez votre code à Heroku et assurez-vous qu'au moins une instance de l'application est en cours d'exécution :

(venv)$ git push heroku master
(venv)$ heroku ps:scale web=1

Exécutez heroku openpour ouvrir votre application dans votre navigateur par défaut.

Vous avez déployé avec succès votre application sur Heroku. Testez-le.

Conclusion

Dans ce didacticiel, vous avez appris à créer une application CRUD avec FastAPI et MongoDB et à la déployer sur Heroku. Effectuez une auto-vérification rapide en passant en revue les objectifs au début du didacticiel. Vous pouvez trouver le code utilisé dans ce tutoriel sur GitHub .

Source :  https://testdrive.io

#crud #fastapi #mongodb #heroku 

Comment Développer Une API Asynchrone Avec FastAPI Et MongoDB

Cómo Desarrollar Una API Asíncrona Con FastAPI Y MongoDB

En este tutorial, aprenderá a desarrollar una API asíncrona con FastAPI y MongoDB . Usaremos el paquete Motor para interactuar con MongoDB de forma asíncrona.

Objetivos

Al final de este tutorial, podrá:

  1. Desarrolle una API RESTful con Python y FastAPI
  2. Interactuar con MongoDB de forma asíncrona
  3. Ejecute MongoDB en la nube con MongoDB Atlas
  4. Implementar una aplicación FastAPI en Heroku

Configuración inicial

Comience creando una nueva carpeta para guardar su proyecto llamada "fastapi-mongo":

$ mkdir fastapi-mongo
$ cd fastapi-mongo

A continuación, cree y active un entorno virtual:

$ python3.9 -m venv venv
$ source venv/bin/activate
$ export PYTHONPATH=$PWD

Siéntete libre de cambiar virtualenv y Pip por Poetry o Pipenv . Para obtener más información, revise Entornos modernos de Python .

A continuación, cree los siguientes archivos y carpetas:

├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       └── routes
└── requirements.txt

Agregue las siguientes dependencias a su archivo requirements.txt :

fastapi==0.73.0
uvicorn==0.17.4

instalarlos:

(venv)$ pip install -r requirements.txt

En el archivo app/main.py , defina un punto de entrada para ejecutar la aplicación:

import uvicorn

if __name__ == "__main__":
    uvicorn.run("server.app:app", host="0.0.0.0", port=8000, reload=True)

Aquí, le indicamos al archivo que ejecute un servidor Uvicorn en el puerto 8000 y que se vuelva a cargar en cada cambio de archivo.

Antes de iniciar el servidor a través del archivo de punto de entrada, cree una ruta base en app/server/app.py :

from fastapi import FastAPI

app = FastAPI()


@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to this fantastic app!"}

Las etiquetas son identificadores que se utilizan para agrupar rutas. Las rutas con las mismas etiquetas se agrupan en una sección de la documentación de la API.

Ejecute el archivo de punto de entrada desde su consola:

(venv)$ python app/main.py

Navegue a http://localhost:8000 en su navegador. Debería ver:

{
  "message": "Welcome to this fantastic app!"
}

También puede ver la documentación de la API interactiva en http://localhost:8000/docs :

interfaz de usuario fastapi swagger

Rutas

Construiremos una aplicación simple para almacenar datos de estudiantes con las siguientes rutas CRUD:

rutas crudas

Antes de sumergirnos en la escritura de las rutas, primero definamos el esquema relevante y configuremos MongoDB.

Esquema

Definamos el esquema en el que se basarán nuestros datos, que representará cómo se almacenan los datos en la base de datos MongoDB.

Los esquemas de Pydantic se utilizan para validar datos junto con serializar (JSON -> Python) y deserializar (Python -> JSON). En otras palabras, no sirve como validador de esquema Mongo.

En la carpeta "aplicación/servidor/modelos", cree un nuevo archivo llamado estudiante.py :

from typing import Optional

from pydantic import BaseModel, EmailStr, Field


class StudentSchema(BaseModel):
    fullname: str = Field(...)
    email: EmailStr = Field(...)
    course_of_study: str = Field(...)
    year: int = Field(..., gt=0, lt=9)
    gpa: float = Field(..., le=4.0)

    class Config:
        schema_extra = {
            "example": {
                "fullname": "John Doe",
                "email": "jdoe@x.edu.ng",
                "course_of_study": "Water resources engineering",
                "year": 2,
                "gpa": "3.0",
            }
        }


class UpdateStudentModel(BaseModel):
    fullname: Optional[str]
    email: Optional[EmailStr]
    course_of_study: Optional[str]
    year: Optional[int]
    gpa: Optional[float]

    class Config:
        schema_extra = {
            "example": {
                "fullname": "John Doe",
                "email": "jdoe@x.edu.ng",
                "course_of_study": "Water resources and environmental engineering",
                "year": 4,
                "gpa": "4.0",
            }
        }


def ResponseModel(data, message):
    return {
        "data": [data],
        "code": 200,
        "message": message,
    }


def ErrorResponseModel(error, code, message):
    return {"error": error, "code": code, "message": message}

En el código anterior, definimos un Pydantic Schema llamado StudentSchemaque representa cómo se almacenarán los datos de los estudiantes en su base de datos MongoDB.

En Pydantic, los puntos suspensivos , ..., indican que se requiere un campo. Podría ser reemplazado con Noneo un valor predeterminado. En StudentSchema, cada campo tiene puntos suspensivos, ya que cada campo es importante y el programa no debe continuar sin tener los valores establecidos.

En el campo gpay yearen el StudentSchema, agregamos los validadores gt , lty le:

  1. gty lten el yearcampo asegura que el valor pasado es mayor que 0 y menor que 9 . Como resultado, valores como 0 , 10 , 11 , generarán errores.
  2. leEl validador en el gpacampo asegura que el valor pasado sea menor o igual a 4.0 .

Este esquema ayudará a los usuarios a enviar solicitudes HTTP con la forma adecuada a la API, es decir, el tipo de datos a enviar y cómo enviarlos.

FastAPI usa Pyantic Schemas para documentar automáticamente modelos de datos junto con Json Schema . Luego, la interfaz de usuario de Swagger representa los datos de los modelos de datos generados. Puede leer más sobre cómo FastAPI genera documentación API aquí .

Como usamos EmailStr, necesitamos instalar email-validator .

Agréguelo al archivo de requisitos:

pydantic[email]

Instalar:

(venv)$ pip install -r requirements.txt

Con el esquema en su lugar, configuremos MongoDB antes de escribir las rutas para la API.

MongoDB

En esta sección, conectaremos MongoDB y configuraremos nuestra aplicación para comunicarse con él.

Según Wikipedia , MongoDB es un programa de base de datos orientado a documentos multiplataforma. Clasificado como un programa de base de datos NoSQL, MongoDB utiliza documentos similares a JSON con esquemas opcionales.

Configuración de MongoDB

Si no tiene MongoDB instalado en su máquina, consulte la guía de instalación de los documentos. Una vez instalado, continúe con la guía para ejecutar el proceso del demonio mongod . Una vez hecho esto, puede verificar que MongoDB esté funcionando conectándose a la instancia a través del mongocomando de shell:

$ mongo

Como referencia, este tutorial utiliza MongoDB Community Edition v5.0.6.

$ mongo --version

MongoDB shell version v5.0.6

Build Info: {
    "version": "5.0.6",
    "gitVersion": "212a8dbb47f07427dae194a9c75baec1d81d9259",
    "modules": [],
    "allocator": "system",
    "environment": {
        "distarch": "x86_64",
        "target_arch": "x86_64"
    }
}

Configuración del motor

A continuación, configuraremos Motor , un controlador MongoDB asíncrono, para interactuar con la base de datos.

Comience agregando la dependencia al archivo de requisitos:

motor==2.5.1

Instalar:

(venv)$ pip install -r requirements.txt

De vuelta en la aplicación, agregue la información de conexión de la base de datos a app/server/database.py :

import motor.motor_asyncio

MONGO_DETAILS = "mongodb://localhost:27017"

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)

database = client.students

student_collection = database.get_collection("students_collection")

En el código anterior, importamos Motor, definimos los detalles de la conexión y creamos un cliente a través de AsyncIOMotorClient .

Luego hicimos referencia a una base de datos llamada studentsy una colección (similar a una tabla en una base de datos relacional) llamada students_collection. Dado que estas son solo referencias y no E/S reales, ninguna requiere una awaitexpresión. Cuando se realiza la primera operación de E/S, tanto la base de datos como la colección se crearán si aún no existen.

A continuación, cree una función de ayuda rápida para analizar los resultados de una consulta de base de datos en un dictado de Python.

Agregue esto también al archivo base de datos.py:

import motor.motor_asyncio

MONGO_DETAILS = "mongodb://localhost:27017"

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)

database = client.students

student_collection = database.get_collection("students_collection")


# helpers


def student_helper(student) -> dict:
    return {
        "id": str(student["_id"]),
        "fullname": student["fullname"],
        "email": student["email"],
        "course_of_study": student["course_of_study"],
        "year": student["year"],
        "GPA": student["gpa"],
    }

A continuación, escribamos las operaciones de la base de datos CRUD.

Operaciones CRUD de base de datos

Comience importando el ObjectIdmétodo del paquete bson en la parte superior del archivo base de datos.py :

from bson.objectid import ObjectId

bson viene instalado como dependencia de motor.

A continuación, agregue cada una de las siguientes funciones para las operaciones CRUD:

# Retrieve all students present in the database
async def retrieve_students():
    students = []
    async for student in student_collection.find():
        students.append(student_helper(student))
    return students


# Add a new student into to the database
async def add_student(student_data: dict) -> dict:
    student = await student_collection.insert_one(student_data)
    new_student = await student_collection.find_one({"_id": student.inserted_id})
    return student_helper(new_student)


# Retrieve a student with a matching ID
async def retrieve_student(id: str) -> dict:
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        return student_helper(student)


# Update a student with a matching ID
async def update_student(id: str, data: dict):
    # Return false if an empty request body is sent.
    if len(data) < 1:
        return False
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        updated_student = await student_collection.update_one(
            {"_id": ObjectId(id)}, {"$set": data}
        )
        if updated_student:
            return True
        return False


# Delete a student from the database
async def delete_student(id: str):
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        await student_collection.delete_one({"_id": ObjectId(id)})
        return True

En el código anterior, definimos las operaciones asincrónicas para crear, leer, actualizar y eliminar datos de estudiantes en la base de datos a través de motor.

En las operaciones de actualización y borrado se busca al alumno en la base de datos para decidir si se realiza o no la operación. Los valores devueltos guían cómo enviar respuestas al usuario, en lo que trabajaremos en la siguiente sección.

Rutas CRUD

En esta sección, agregaremos las rutas para complementar las operaciones de la base de datos en el archivo de la base de datos.

En la carpeta "rutas", cree un nuevo archivo llamado student.py y agréguele el siguiente contenido:

from fastapi import APIRouter, Body
from fastapi.encoders import jsonable_encoder

from app.server.database import (
    add_student,
    delete_student,
    retrieve_student,
    retrieve_students,
    update_student,
)
from app.server.models.student import (
    ErrorResponseModel,
    ResponseModel,
    StudentSchema,
    UpdateStudentModel,
)

router = APIRouter()

Usaremos el codificador compatible con JSON de FastAPI para convertir nuestros modelos a un formato que sea compatible con JSON.

Luego, conecta la ruta del estudiante en app/server/app.py :

from fastapi import FastAPI

from app.server.routes.student import router as StudentRouter

app = FastAPI()

app.include_router(StudentRouter, tags=["Student"], prefix="/student")


@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to this fantastic app!"}

Crear

De vuelta en el archivo de rutas, agregue el siguiente controlador para crear un nuevo estudiante:

@router.post("/", response_description="Student data added into the database")
async def add_student_data(student: StudentSchema = Body(...)):
    student = jsonable_encoder(student)
    new_student = await add_student(student)
    return ResponseModel(new_student, "Student added successfully.")

Entonces, la ruta espera una carga útil que coincida con el formato de StudentSchema. Ejemplo:

{
    "fullname": "John Doe",
    "email": "jdoe@x.edu.ng",
    "course_of_study": "Water resources engineering",
    "year": 2,
    "gpa": "3.0",
}

Inicie el servidor Uvicorn:

(venv)$ python app/main.py

Y actualice la página de documentación de la API interactiva en http://localhost:8000/docs para ver la nueva ruta:

arrogancia de la interfaz de usuario

Pruébalo también:

arrogancia de la interfaz de usuario

Entonces, cuando se envía una solicitud al punto final, almacena un cuerpo de solicitud codificado en JSON en la variable studentantes de llamar al add_studentmétodo de la base de datos y almacenar la respuesta en la new_studentvariable. Luego, la respuesta de la base de datos se devuelve a través del ResponseModel.

Pruebe también los validadores:

  1. El año debe ser mayor que 0 y menor que 10
  2. El GPA debe ser menor o igual a 4.0

arrogancia de la interfaz de usuario

Leer

Siguiendo adelante, agregue las siguientes rutas para recuperar a todos los estudiantes y a un solo estudiante:

@router.get("/", response_description="Students retrieved")
async def get_students():
    students = await retrieve_students()
    if students:
        return ResponseModel(students, "Students data retrieved successfully")
    return ResponseModel(students, "Empty list returned")


@router.get("/{id}", response_description="Student data retrieved")
async def get_student_data(id):
    student = await retrieve_student(id)
    if student:
        return ResponseModel(student, "Student data retrieved successfully")
    return ErrorResponseModel("An error occurred.", 404, "Student doesn't exist.")

arrogancia de la interfaz de usuario

¿Qué sucede si no pasa un ObjectId válido, por ejemplo, 1para que el ID recupere la ruta de un solo estudiante? ¿Cómo puede manejar mejor esto en la aplicación?

Cuando se implemente la operación de eliminación, tendrá la oportunidad de probar la respuesta para una base de datos vacía.

Actualizar

Next, write the individual route for updating the student data:

@router.put("/{id}")
async def update_student_data(id: str, req: UpdateStudentModel = Body(...)):
    req = {k: v for k, v in req.dict().items() if v is not None}
    updated_student = await update_student(id, req)
    if updated_student:
        return ResponseModel(
            "Student with ID: {} name update is successful".format(id),
            "Student name updated successfully",
        )
    return ErrorResponseModel(
        "An error occurred",
        404,
        "There was an error updating the student data.",
    )

arrogancia de la interfaz de usuario

Delete

Finally, add the delete route:

@router.delete("/{id}", response_description="Student data deleted from the database")
async def delete_student_data(id: str):
    deleted_student = await delete_student(id)
    if deleted_student:
        return ResponseModel(
            "Student with ID: {} removed".format(id), "Student deleted successfully"
        )
    return ErrorResponseModel(
        "An error occurred", 404, "Student with id {0} doesn't exist".format(id)
    )

Retrieve the ID of the user you created earlier and test the delete route:

arrogancia de la interfaz de usuario

Remove any remaining students and test out the read routes again, ensuring the responses are appropriate for an empty database.

Deployment

In this section, we'll deploy the app to Heroku and configure a cloud database for MongoDB.

MongoDB Atlas

Before deploying, we need to set up MongoDB Atlas, a cloud database service for MongoDB to host our database.

Follow the Getting Started guide where you'll create an account, deploy a free tier cluster, set up a user, and whitelist an IP address.

Para fines de prueba, use 0.0.0.0/0la IP incluida en la lista blanca para permitir el acceso desde cualquier lugar. Para una aplicación de producción, querrá restringir el acceso a una IP estática.

Una vez hecho esto, obtenga la información de conexión de la base de datos de su clúster haciendo clic en el botón "Conectar":

atlas mongodb

Haz clic en la segunda opción, "Conéctate a tu aplicación":

atlas mongodb

Copie la URL de conexión, asegurándose de actualizar la contraseña. Establezca la base de datos predeterminada en "estudiantes" también. Se verá similar a:

mongodb+srv://foobar:foobar@cluster0.0reol.mongodb.net/students?retryWrites=true&w=majority

En lugar de codificar este valor en nuestra aplicación, definiremos que tiene una variable de entorno. Cree un nuevo archivo llamado .env en la raíz del proyecto y la información de conexión:

MONGO_DETAILS=your_connection_url

Asegúrese de reemplazar your_connection_urlcon la URL copiada.

A continuación, para simplificar la gestión de las variables de entorno en nuestra aplicación, instalemos el paquete Python Decouple . Agréguelo a su archivo de requisitos así:

python-decouple==3.6

Instalar:

(venv)$ pip install -r requirements.txt

En el archivo app/server/database.py , importe la biblioteca:

from decouple import config

El método importado configbusca en el directorio raíz un archivo .env y lee el contenido que se le pasa. Entonces, en nuestro caso, leerá la MONGO_DETAILSvariable.

A continuación, cambie la MONGO_DETAILSvariable a:

MONGO_DETAILS = config("MONGO_DETAILS")  # read environment variable

Pruebas locales

Antes de implementar, probemos la aplicación localmente con la base de datos en la nube para asegurarnos de que la conexión esté configurada correctamente. Reinicie su servidor Uvicorn y pruebe cada ruta desde la documentación interactiva en http://localhost:8000/docs .

Debería poder ver los datos en el tablero de Atlas:

atlas mongodb

Implementación en Heroku

Finalmente, implementemos la aplicación en Heroku .

Heroku es una plataforma en la nube como servicio (PaaS) que se utiliza para implementar y escalar aplicaciones.

Si es necesario, regístrese para obtener una cuenta de Heroku e instale la CLI de Heroku .

Antes de continuar, cree un archivo .gitignore en el proyecto para evitar registrar la carpeta "venv" y el archivo .env en git:

(venv)$ touch .gitignore

Agregue lo siguiente:

.env
venv/
__pycache__

A continuación, agregue un Procfile a la raíz de su proyecto:

web: uvicorn app.server.app:app --host 0.0.0.0 --port=$PORT

Notas:

  1. Un Procfile es un archivo de texto, ubicado en la raíz de su proyecto, que guía a Heroku sobre cómo ejecutar su aplicación. Como estamos sirviendo una aplicación web, definimos el tipo de proceso webjunto con el comando para servir Uvicorn.
  2. Heroku expone dinámicamente un puerto para que su aplicación se ejecute en el momento de la implementación, que se expone a través de la $PORTvariable de entorno.

Su proyecto ahora debería tener los siguientes archivos y carpetas:

├── .env
├── .gitignore
├── Procfile
├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       │   └── student.py
│       └── routes
│           └── student.py
└── requirements.txt

En la raíz de tu proyecto, inicializa un nuevo repositorio git:

(venv)$ git init
(venv)$ git add .
(venv)$ git commit -m "My fastapi and mongo application"

Ahora, podemos crear una nueva aplicación en Heroku:

(venv)$ heroku create

Junto con la creación de una nueva aplicación, este comando crea un repositorio git remoto en Heroku para que podamos impulsar nuestra aplicación para su implementación. Luego establece esto como un control remoto en el repositorio local automáticamente para nosotros.

Puede verificar que el control remoto esté configurado ejecutando git remote -v.

Tome nota de la URL de su aplicación.

Como no agregamos el archivo .env a git, debemos configurar la variable de entorno dentro del entorno de Heroku:

(venv)$ heroku config:set MONGO_DETAILS="your_mongo_connection_url"

Nuevamente, asegúrese de reemplazar your_connection_urlcon la URL de conexión real.

Envíe su código a Heroku y asegúrese de que se esté ejecutando al menos una instancia de la aplicación:

(venv)$ git push heroku master
(venv)$ heroku ps:scale web=1

Ejecutar heroku openpara abrir su aplicación en su navegador predeterminado.

Ha implementado correctamente su aplicación en Heroku. Pruébelo.

Conclusión

En este tutorial, aprendió cómo crear una aplicación CRUD con FastAPI y MongoDB e implementarla en Heroku. Realice una autocomprobación rápida revisando los objetivos al comienzo del tutorial. Puede encontrar el código utilizado en este tutorial en GitHub .

Fuente:  https://testdriven.io

#crud #fastapi #mongodb #heroku 

Cómo Desarrollar Una API Asíncrona Con FastAPI Y MongoDB
Neil  Morgan

Neil Morgan

1660168020

Como Desenvolver Uma API Assíncrona Com FastAPI E MongoDB

Neste tutorial, você aprenderá a desenvolver uma API assíncrona com FastAPI e MongoDB . Usaremos o pacote Motor para interagir com o MongoDB de forma assíncrona.

Objetivos

Ao final deste tutorial, você será capaz de:

  1. Desenvolva uma API RESTful com Python e FastAPI
  2. Interagir com o MongoDB de forma assíncrona
  3. Execute o MongoDB na nuvem com o MongoDB Atlas
  4. Implantar um aplicativo FastAPI no Heroku

Configuração inicial

Comece criando uma nova pasta para armazenar seu projeto chamada "fastapi-mongo":

$ mkdir fastapi-mongo
$ cd fastapi-mongo

Em seguida, crie e ative um ambiente virtual:

$ python3.9 -m venv venv
$ source venv/bin/activate
$ export PYTHONPATH=$PWD

Sinta-se à vontade para trocar virtualenv e Pip por Poetry ou Pipenv . Para saber mais, revise Ambientes Python Modernos .

Em seguida, crie os seguintes arquivos e pastas:

├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       └── routes
└── requirements.txt

Adicione as seguintes dependências ao seu arquivo requirements.txt :

fastapi==0.73.0
uvicorn==0.17.4

Instale-os:

(venv)$ pip install -r requirements.txt

No arquivo app/main.py , defina um ponto de entrada para executar o aplicativo:

import uvicorn

if __name__ == "__main__":
    uvicorn.run("server.app:app", host="0.0.0.0", port=8000, reload=True)

Aqui, instruímos o arquivo para executar um servidor Uvicorn na porta 8000 e recarregar a cada alteração de arquivo.

Antes de iniciar o servidor por meio do arquivo de ponto de entrada, crie uma rota base em app/server/app.py :

from fastapi import FastAPI

app = FastAPI()


@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to this fantastic app!"}

Tags são identificadores usados ​​para agrupar rotas. As rotas com as mesmas tags são agrupadas em uma seção na documentação da API.

Execute o arquivo de ponto de entrada do seu console:

(venv)$ python app/main.py

Navegue até http://localhost:8000 em seu navegador. Você deveria ver:

{
  "message": "Welcome to this fantastic app!"
}

Você também pode visualizar a documentação interativa da API em http://localhost:8000/docs :

fastapi swagger ui

Rotas

Construiremos um aplicativo simples para armazenar dados de alunos com as seguintes rotas CRUD:

rotas cruas

Antes de mergulharmos na escrita das rotas, vamos primeiro definir o esquema relevante e configurar o MongoDB.

Esquema

Vamos definir o Schema para o qual nossos dados serão baseados, que representará como os dados são armazenados no banco de dados MongoDB.

Os esquemas Pydantic são usados ​​para validar dados juntamente com serialização (JSON -> Python) e desserialização (Python -> JSON). Ele não serve como um validador de esquema do Mongo , em outras palavras.

Na pasta "app/server/models", crie um novo arquivo chamado student.py :

from typing import Optional

from pydantic import BaseModel, EmailStr, Field


class StudentSchema(BaseModel):
    fullname: str = Field(...)
    email: EmailStr = Field(...)
    course_of_study: str = Field(...)
    year: int = Field(..., gt=0, lt=9)
    gpa: float = Field(..., le=4.0)

    class Config:
        schema_extra = {
            "example": {
                "fullname": "John Doe",
                "email": "jdoe@x.edu.ng",
                "course_of_study": "Water resources engineering",
                "year": 2,
                "gpa": "3.0",
            }
        }


class UpdateStudentModel(BaseModel):
    fullname: Optional[str]
    email: Optional[EmailStr]
    course_of_study: Optional[str]
    year: Optional[int]
    gpa: Optional[float]

    class Config:
        schema_extra = {
            "example": {
                "fullname": "John Doe",
                "email": "jdoe@x.edu.ng",
                "course_of_study": "Water resources and environmental engineering",
                "year": 4,
                "gpa": "4.0",
            }
        }


def ResponseModel(data, message):
    return {
        "data": [data],
        "code": 200,
        "message": message,
    }


def ErrorResponseModel(error, code, message):
    return {"error": error, "code": code, "message": message}

No código acima, definimos um Pydantic Schema chamado StudentSchemaque representa como os dados do aluno serão armazenados em seu banco de dados MongoDB.

Em Pydantic, as reticências , ..., indicam que um campo é obrigatório. Ele pode ser substituído por Noneou por um valor padrão. Em StudentSchema, cada campo tem reticências, pois cada campo é importante e o programa não deve prosseguir sem ter os valores configurados.

No campo gpae do , adicionamos os validadores , , e :yearStudentSchema gtltle

  1. gte ltno yearcampo garante que o valor passado seja maior que 0 e menor que 9 . Como resultado, valores como 0 , 10 , 11 , resultarão em erros.
  2. levalidador no gpacampo garante que o valor passado seja menor ou igual a 4.0 .

Esse esquema ajudará os usuários a enviar solicitações HTTP com a forma adequada para a API -- ou seja, o tipo de dados a serem enviados e como enviá-los.

FastAPI usa Pyantic Schemas para documentar automaticamente modelos de dados em conjunto com Json Schema . A interface do usuário do Swagger renderiza os dados dos modelos de dados gerados. Você pode ler mais sobre como o FastAPI gera a documentação da API aqui .

Como usamos EmailStro , precisamos instalar o email-validator .

Adicione-o ao arquivo de requisitos:

pydantic[email]

Instalar:

(venv)$ pip install -r requirements.txt

Com o esquema em vigor, vamos configurar o MongoDB antes de escrever as rotas para a API.

MongoDB

Nesta seção, conectaremos o MongoDB e configuraremos nosso aplicativo para se comunicar com ele.

De acordo com a Wikipedia , o MongoDB é um programa de banco de dados orientado a documentos multiplataforma. Classificado como um programa de banco de dados NoSQL, o MongoDB usa documentos semelhantes a JSON com esquemas opcionais.

Configuração do MongoDB

Se você não tiver o MongoDB instalado em sua máquina, consulte o guia de instalação da documentação. Uma vez instalado, continue com o guia para executar o processo do mongod daemon. Uma vez feito, você pode verificar se o MongoDB está funcionando, conectando-se à instância por meio do mongocomando shell:

$ mongo

Para referência, este tutorial usa o MongoDB Community Edition v5.0.6.

$ mongo --version

MongoDB shell version v5.0.6

Build Info: {
    "version": "5.0.6",
    "gitVersion": "212a8dbb47f07427dae194a9c75baec1d81d9259",
    "modules": [],
    "allocator": "system",
    "environment": {
        "distarch": "x86_64",
        "target_arch": "x86_64"
    }
}

Configuração do motor

Em seguida, vamos configurar o Motor , um driver assíncrono do MongoDB, para interagir com o banco de dados.

Comece adicionando a dependência ao arquivo de requisitos:

motor==2.5.1

Instalar:

(venv)$ pip install -r requirements.txt

De volta ao aplicativo, adicione as informações de conexão do banco de dados a app/server/database.py :

import motor.motor_asyncio

MONGO_DETAILS = "mongodb://localhost:27017"

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)

database = client.students

student_collection = database.get_collection("students_collection")

No código acima, importamos Motor, definimos os detalhes da conexão e criamos um cliente via AsyncIOMotorClient .

Em seguida, referenciamos um banco de dados chamado studentse uma coleção (semelhante a uma tabela em um banco de dados relacional) chamada students_collection. Como essas são apenas referências e não E/S reais, nenhuma delas requer uma awaitexpressão. Quando a primeira operação de E/S for feita, o banco de dados e a coleção serão criados, caso ainda não existam.

Em seguida, crie uma função auxiliar rápida para analisar os resultados de uma consulta de banco de dados em um dict do Python.

Adicione isso ao arquivo database.py também:

import motor.motor_asyncio

MONGO_DETAILS = "mongodb://localhost:27017"

client = motor.motor_asyncio.AsyncIOMotorClient(MONGO_DETAILS)

database = client.students

student_collection = database.get_collection("students_collection")


# helpers


def student_helper(student) -> dict:
    return {
        "id": str(student["_id"]),
        "fullname": student["fullname"],
        "email": student["email"],
        "course_of_study": student["course_of_study"],
        "year": student["year"],
        "GPA": student["gpa"],
    }

Em seguida, vamos escrever as operações do banco de dados CRUD.

Operações CRUD do banco de dados

Comece importando o ObjectIdmétodo do pacote bson na parte superior do arquivo database.py :

from bson.objectid import ObjectId

bson vem instalado como uma dependência do motor.

Em seguida, adicione cada uma das seguintes funções para as operações CRUD:

# Retrieve all students present in the database
async def retrieve_students():
    students = []
    async for student in student_collection.find():
        students.append(student_helper(student))
    return students


# Add a new student into to the database
async def add_student(student_data: dict) -> dict:
    student = await student_collection.insert_one(student_data)
    new_student = await student_collection.find_one({"_id": student.inserted_id})
    return student_helper(new_student)


# Retrieve a student with a matching ID
async def retrieve_student(id: str) -> dict:
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        return student_helper(student)


# Update a student with a matching ID
async def update_student(id: str, data: dict):
    # Return false if an empty request body is sent.
    if len(data) < 1:
        return False
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        updated_student = await student_collection.update_one(
            {"_id": ObjectId(id)}, {"$set": data}
        )
        if updated_student:
            return True
        return False


# Delete a student from the database
async def delete_student(id: str):
    student = await student_collection.find_one({"_id": ObjectId(id)})
    if student:
        await student_collection.delete_one({"_id": ObjectId(id)})
        return True

No código acima, definimos as operações assíncronas para criar, ler, atualizar e excluir os dados do aluno no banco de dados via motor.

Nas operações de atualização e exclusão, o aluno é procurado no banco de dados para decidir se realiza ou não a operação. Os valores de retorno orientam como enviar respostas ao usuário em que trabalharemos na próxima seção.

Rotas CRUD

Nesta seção, adicionaremos as rotas para complementar as operações do banco de dados no arquivo de banco de dados.

Na pasta "routes", crie um novo arquivo chamado student.py e adicione o seguinte conteúdo a ele:

from fastapi import APIRouter, Body
from fastapi.encoders import jsonable_encoder

from app.server.database import (
    add_student,
    delete_student,
    retrieve_student,
    retrieve_students,
    update_student,
)
from app.server.models.student import (
    ErrorResponseModel,
    ResponseModel,
    StudentSchema,
    UpdateStudentModel,
)

router = APIRouter()

Usaremos o codificador compatível com JSON da FastAPI para converter nossos modelos em um formato compatível com JSON.

Em seguida, conecte a rota do aluno em app/server/app.py :

from fastapi import FastAPI

from app.server.routes.student import router as StudentRouter

app = FastAPI()

app.include_router(StudentRouter, tags=["Student"], prefix="/student")


@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to this fantastic app!"}

Crio

De volta ao arquivo de rotas, adicione o seguinte manipulador para criar um novo aluno:

@router.post("/", response_description="Student data added into the database")
async def add_student_data(student: StudentSchema = Body(...)):
    student = jsonable_encoder(student)
    new_student = await add_student(student)
    return ResponseModel(new_student, "Student added successfully.")

Portanto, a rota espera uma carga útil que corresponda ao formato de StudentSchema. Exemplo:

{
    "fullname": "John Doe",
    "email": "jdoe@x.edu.ng",
    "course_of_study": "Water resources engineering",
    "year": 2,
    "gpa": "3.0",
}

Inicie o servidor Uvicorn:

(venv)$ python app/main.py

E atualize a página de documentação da API interativa em http://localhost:8000/docs para ver a nova rota:

swagger ui

Faça o teste também:

swagger ui

Portanto, quando uma solicitação é enviada ao endpoint, ele armazena um corpo de solicitação codificado em JSON na variável studentantes de chamar o add_studentmétodo de banco de dados e armazenar a resposta na new_studentvariável. A resposta do banco de dados é então retornada por meio do arquivo ResponseModel.

Teste também os validadores:

  1. O ano deve ser maior que 0 e menor que 10
  2. O GPA deve ser menor ou igual a 4,0

swagger ui

Ler

Seguindo em frente, adicione as seguintes rotas para recuperar todos os alunos e um único aluno:

@router.get("/", response_description="Students retrieved")
async def get_students():
    students = await retrieve_students()
    if students:
        return ResponseModel(students, "Students data retrieved successfully")
    return ResponseModel(students, "Empty list returned")


@router.get("/{id}", response_description="Student data retrieved")
async def get_student_data(id):
    student = await retrieve_student(id)
    if student:
        return ResponseModel(student, "Student data retrieved successfully")
    return ErrorResponseModel("An error occurred.", 404, "Student doesn't exist.")

swagger ui

O que acontece se você não passar um ObjectId válido -- por exemplo, 1-- para o ID para recuperar uma única rota de aluno? Como você pode lidar melhor com isso no aplicativo?

Quando a operação de exclusão for implementada, você terá a oportunidade de testar a resposta para um banco de dados vazio.

Atualizar

Em seguida, escreva a rota individual para atualizar os dados do aluno:

@router.put("/{id}")
async def update_student_data(id: str, req: UpdateStudentModel = Body(...)):
    req = {k: v for k, v in req.dict().items() if v is not None}
    updated_student = await update_student(id, req)
    if updated_student:
        return ResponseModel(
            "Student with ID: {} name update is successful".format(id),
            "Student name updated successfully",
        )
    return ErrorResponseModel(
        "An error occurred",
        404,
        "There was an error updating the student data.",
    )

swagger ui

Excluir

Por fim, adicione a rota de exclusão:

@router.delete("/{id}", response_description="Student data deleted from the database")
async def delete_student_data(id: str):
    deleted_student = await delete_student(id)
    if deleted_student:
        return ResponseModel(
            "Student with ID: {} removed".format(id), "Student deleted successfully"
        )
    return ErrorResponseModel(
        "An error occurred", 404, "Student with id {0} doesn't exist".format(id)
    )

Recupere o ID do usuário que você criou anteriormente e teste a rota de exclusão:

swagger ui

Remova todos os alunos restantes e teste as rotas de leitura novamente, garantindo que as respostas sejam apropriadas para um banco de dados vazio.

Implantação

Nesta seção, implantaremos o aplicativo no Heroku e configuraremos um banco de dados em nuvem para o MongoDB.

Atlas MongoDB

Antes de implantar, precisamos configurar o MongoDB Atlas , um serviço de banco de dados em nuvem para o MongoDB hospedar nosso banco de dados.

Siga o guia de introdução onde você criará uma conta, implantará um cluster de camada gratuita, configurará um usuário e colocará um endereço IP na lista de permissões.

Para fins de teste, use 0.0.0.0/0para o IP da lista de permissões para permitir o acesso de qualquer lugar. Para um aplicativo de produção, você desejará restringir o acesso a um IP estático.

Uma vez feito, pegue as informações de conexão do banco de dados do seu cluster clicando no botão "Conectar":

atlas mongodb

Clique na segunda opção, "Conectar ao seu aplicativo":

atlas mongodb

Copie o URL de conexão, certificando-se de atualizar a senha. Defina o banco de dados padrão para "alunos" também. Será semelhante a:

mongodb+srv://foobar:foobar@cluster0.0reol.mongodb.net/students?retryWrites=true&w=majority

Em vez de codificar esse valor em nosso aplicativo, vamos defini-lo como uma variável de ambiente. Crie um novo arquivo chamado .env na raiz do projeto e as informações de conexão para ele:

MONGO_DETAILS=your_connection_url

Certifique-se de substituir your_connection_urlpelo URL copiado.

Em seguida, para simplificar o gerenciamento de variáveis ​​de ambiente em nosso aplicativo, vamos instalar o pacote Python Decouple . Adicione-o ao seu arquivo de requisitos assim:

python-decouple==3.6

Instalar:

(venv)$ pip install -r requirements.txt

No arquivo app/server/database.py , importe a biblioteca:

from decouple import config

O método importado configvarre o diretório raiz em busca de um arquivo .env e lê o conteúdo passado para ele. Então, no nosso caso, ele vai ler a MONGO_DETAILSvariável.

Em seguida, altere a MONGO_DETAILSvariável para:

MONGO_DETAILS = config("MONGO_DETAILS")  # read environment variable

Testando localmente

Antes de implantar, vamos testar o aplicativo localmente com o banco de dados em nuvem para garantir que a conexão esteja configurada corretamente. Reinicie seu servidor Uvicorn e teste cada rota da documentação interativa em http://localhost:8000/docs .

Você deve conseguir ver os dados no painel do Atlas:

atlas mongodb

Implantando no Heroku

Por fim, vamos implantar o aplicativo no Heroku .

Heroku é uma plataforma de nuvem como serviço (PaaS) usada para implantar e dimensionar aplicativos.

Se necessário, inscreva-se em uma conta Heroku e instale o Heroku CLI .

Antes de continuar, crie um arquivo .gitignore no projeto para evitar o check-in da pasta "venv" e do arquivo .env no git:

(venv)$ touch .gitignore

Adicione o seguinte:

.env
venv/
__pycache__

Em seguida, adicione um Procfile à raiz do seu projeto:

web: uvicorn app.server.app:app --host 0.0.0.0 --port=$PORT

Notas:

  1. Um Procfile é um arquivo de texto, colocado na raiz do seu projeto, que orienta o Heroku sobre como executar seu aplicativo. Como estamos servindo um aplicativo da web, definimos o tipo de processo webjunto com o comando para servir o Uvicorn.
  2. O Heroku expõe dinamicamente uma porta para que seu aplicativo seja executado no momento da implantação, que é exposta por meio da $PORTvariável de ambiente.

Seu projeto agora deve ter os seguintes arquivos e pastas:

├── .env
├── .gitignore
├── Procfile
├── app
│   ├── __init__.py
│   ├── main.py
│   └── server
│       ├── app.py
│       ├── database.py
│       ├── models
│       │   └── student.py
│       └── routes
│           └── student.py
└── requirements.txt

Na raiz do seu projeto, inicialize um novo repositório git:

(venv)$ git init
(venv)$ git add .
(venv)$ git commit -m "My fastapi and mongo application"

Agora, podemos criar um novo aplicativo no Heroku:

(venv)$ heroku create

Além de criar um novo aplicativo, esse comando cria um repositório git remoto no Heroku para enviarmos nosso aplicativo para implantação. Em seguida, ele define isso como um controle remoto no repositório local automaticamente para nós.

Você pode verificar se o controle remoto está configurado executando git remote -v.

Anote o URL do seu aplicativo.

Como não adicionamos o arquivo .env ao git, precisamos definir a variável de ambiente no ambiente Heroku:

(venv)$ heroku config:set MONGO_DETAILS="your_mongo_connection_url"

Novamente, certifique-se de substituir your_connection_urlpelo URL de conexão real.

Envie seu código para o Heroku e certifique-se de que pelo menos uma instância do aplicativo esteja em execução:

(venv)$ git push heroku master
(venv)$ heroku ps:scale web=1

Execute heroku openpara abrir seu aplicativo em seu navegador padrão.

Você implantou com sucesso seu aplicativo no Heroku. Teste-o.

Conclusão

Neste tutorial, você aprendeu como criar um aplicativo CRUD com FastAPI e MongoDB e implantá-lo no Heroku. Faça uma autoverificação rápida revisando os objetivos no início do tutorial. Você pode encontrar o código usado neste tutorial no GitHub .

Fonte:  https://testdrive.io

#crud #fastapi #mongodb #heroku 

Como Desenvolver Uma API Assíncrona Com FastAPI E MongoDB