Chargement...
Aucun résultat.

    Testez vos connaissances et partagez-les avec notre communauté
    done
    Accédez à plus de 700 ateliers pratiques, badges de compétence et cours

    Développer une API REST avec Go et Cloud Run

    Atelier 1 heure universal_currency_alt 5 crédits show_chart Intermédiaire
    info Cet atelier peut intégrer des outils d'IA pour vous accompagner dans votre apprentissage.
    Testez vos connaissances et partagez-les avec notre communauté
    done
    Accédez à plus de 700 ateliers pratiques, badges de compétence et cours

    GSP761

    Google Cloud – Ateliers adaptés au rythme de chacun

    Logo Pet Theory

    Présentation

    Dans les ateliers du cours Serverless Cloud Run Development, vous allez découvrir un scénario métier fondé sur une entreprise fictive et aider les protagonistes à migrer vers une technologie sans serveur.

    Il y a 12 ans, Lily a créé une chaîne de cliniques vétérinaires appelée Pet Theory. L'entreprise s'est beaucoup développée, et Lily passe désormais plus de temps à traiter des dossiers au téléphone avec les compagnies d'assurance qu'à s'occuper des animaux. Ce serait tellement plus simple si les compagnies d'assurance pouvaient consulter en ligne le coût total des traitements.

    Lors des précédents ateliers de cette série, Ruby, la consultante en informatique et Patrick, l'ingénieur DevOps, ont transféré la base de données client de Pet Theory vers une base de données Firestore sans serveur dans le cloud, puis en ont donné l'accès aux clients afin qu'ils puissent prendre rendez-vous en ligne. L'équipe de développement de Pet Theory étant composée d'une seule personne, elle a besoin d'une solution sans serveur qui ne nécessite pas beaucoup de maintenance.

    Dans cet atelier, vous allez aider Ruby et Patrick à donner aux compagnies d'assurance un accès à des données client, sans exposer d'informations permettant d'identifier l'utilisateur. Vous allez créer une passerelle API REST (Representational State Transfer) sécurisée à l'aide de Cloud Run, qui fonctionne sans serveur. Les compagnies d'assurance pourront ainsi voir le coût total des traitements sans accéder aux informations personnelles des clients.

    Objectifs

    Au cours de cet atelier, vous allez apprendre à réaliser les opérations suivantes :

    • Développer une API REST avec Go
    • Importer des données client de test dans Firestore
    • Connecter l'API REST à la base de données Firestore
    • Déployer l'API REST sur Cloud Run

    Prérequis

    Il s'agit d'un atelier de niveau intermédiaire destiné aux personnes qui maîtrisent déjà la console Cloud et les environnements Cloud Shell. Cet atelier fait partie d'une série en plusieurs parties. Il est recommandé de suivre les ateliers précédents (listés ci-dessous), mais ce n'est pas obligatoire :

    • Importer des données dans une base de données sans serveur
    • Créer une application Web sans serveur avec Firebase et Firestore
    • Créer une application sans serveur qui permet de produire des fichiers PDF

    Préparation

    Avant de cliquer sur le bouton "Démarrer l'atelier"

    Lisez ces instructions. Les ateliers sont minutés, et vous ne pouvez pas les mettre en pause. Le minuteur, qui démarre lorsque vous cliquez sur Démarrer l'atelier, indique combien de temps les ressources Google Cloud resteront accessibles.

    Cet atelier pratique vous permet de suivre vous-même les activités dans un véritable environnement cloud, et non dans un environnement de simulation ou de démonstration. Nous vous fournissons des identifiants temporaires pour vous connecter à Google Cloud le temps de l'atelier.

    Pour réaliser cet atelier :

    • vous devez avoir accès à un navigateur Internet standard (nous vous recommandons d'utiliser Chrome) ;
    Remarque : Ouvrez une fenêtre de navigateur en mode incognito/navigation privée pour effectuer cet atelier. Vous éviterez ainsi les conflits entre votre compte personnel et le temporaire étudiant, qui pourraient entraîner des frais supplémentaires facturés sur votre compte personnel.
    • vous disposez d'un temps limité ; une fois l'atelier commencé, vous ne pouvez pas le mettre en pause.
    Remarque : Si vous possédez déjà votre propre compte ou projet Google Cloud, veillez à ne pas l'utiliser pour réaliser cet atelier afin d'éviter que des frais supplémentaires ne vous soient facturés.

    Démarrer l'atelier et se connecter à la console Google Cloud

    1. Cliquez sur le bouton Démarrer l'atelier. Si l'atelier est payant, un pop-up s'affiche pour vous permettre de sélectionner un mode de paiement. Sur la gauche, vous trouverez le panneau Détails concernant l'atelier, qui contient les éléments suivants :

      • Le bouton Ouvrir la console Google Cloud
      • Le temps restant
      • Les identifiants temporaires que vous devez utiliser pour cet atelier
      • Des informations complémentaires vous permettant d'effectuer l'atelier
    2. Cliquez sur Ouvrir la console Google Cloud (ou effectuez un clic droit et sélectionnez Ouvrir le lien dans la fenêtre de navigation privée si vous utilisez le navigateur Chrome).

      L'atelier lance les ressources, puis ouvre la page Se connecter dans un nouvel onglet.

      Conseil : Réorganisez les onglets dans des fenêtres distinctes, placées côte à côte.

      Remarque : Si la boîte de dialogue Sélectionner un compte s'affiche, cliquez sur Utiliser un autre compte.
    3. Si nécessaire, copiez le nom d'utilisateur ci-dessous et collez-le dans la boîte de dialogue Se connecter.

      {{{user_0.username | "Username"}}}

      Vous trouverez également le nom d'utilisateur dans le panneau Détails concernant l'atelier.

    4. Cliquez sur Suivant.

    5. Copiez le mot de passe ci-dessous et collez-le dans la boîte de dialogue Bienvenue.

      {{{user_0.password | "Password"}}}

      Vous trouverez également le mot de passe dans le panneau Détails concernant l'atelier.

    6. Cliquez sur Suivant.

      Important : Vous devez utiliser les identifiants fournis pour l'atelier. Ne saisissez pas ceux de votre compte Google Cloud. Remarque : Si vous utilisez votre propre compte Google Cloud pour cet atelier, des frais supplémentaires peuvent vous être facturés.
    7. Accédez aux pages suivantes :

      • Acceptez les conditions d'utilisation.
      • N'ajoutez pas d'options de récupération ni d'authentification à deux facteurs (ce compte est temporaire).
      • Ne vous inscrivez pas à des essais gratuits.

    Après quelques instants, la console Cloud s'ouvre dans cet onglet.

    Remarque : Pour afficher un menu contenant la liste des produits et services Google Cloud, cliquez sur le menu de navigation en haut à gauche. Icône du menu de navigation

    Activer Cloud Shell

    Cloud Shell est une machine virtuelle qui contient de nombreux outils pour les développeurs. Elle comprend un répertoire d'accueil persistant de 5 Go et s'exécute sur Google Cloud. Cloud Shell vous permet d'accéder via une ligne de commande à vos ressources Google Cloud.

    1. Cliquez sur Activer Cloud Shell Icône Activer Cloud Shell en haut de la console Google Cloud.

    Une fois connecté, vous êtes en principe authentifié et le projet est défini sur votre ID_PROJET. Le résultat contient une ligne qui déclare YOUR_PROJECT_ID (VOTRE_ID_PROJET) pour cette session :

    Your Cloud Platform project in this session is set to YOUR_PROJECT_ID

    gcloud est l'outil de ligne de commande pour Google Cloud. Il est préinstallé sur Cloud Shell et permet la complétion par tabulation.

    1. (Facultatif) Vous pouvez lister les noms des comptes actifs à l'aide de cette commande :
    gcloud auth list
    1. Cliquez sur Autoriser.

    2. Vous devez à présent obtenir le résultat suivant :

    Résultat :

    ACTIVE: * ACCOUNT: student-01-xxxxxxxxxxxx@qwiklabs.net To set the active account, run: $ gcloud config set account `ACCOUNT`
    1. (Facultatif) Vous pouvez lister les ID de projet à l'aide de cette commande :
    gcloud config list project

    Résultat :

    [core] project = <ID_Projet>

    Exemple de résultat :

    [core] project = qwiklabs-gcp-44776a13dea667a6 Remarque : Pour consulter la documentation complète sur gcloud, dans Google Cloud, accédez au guide de présentation de la gcloud CLI.

    Lily

    Lily, fondatrice de Pet Theory

    Bonjour Ruby,

    La semaine dernière, je vous ai indiqué que j'étais submergée par les dossiers et les appels téléphoniques des compagnies d'assurance. Y a-t-il un moyen de leur permettre d'accéder à des données client de manière efficace et sécurisée ?

    La charge de travail actuelle devient ingérable. Pouvez-vous m'aider ?

    Lily

    Ruby

    Ruby, Consultante en logiciels

    Bonjour Lily,

    J'ai déjeuné avec Patrick hier, et nous avons élaboré un plan pour faciliter l'accès sécurisé de tiers autorisés aux fichiers numériques de Pet Theory.

    Ce plan comprend quatre étapes :

    1. Créer une API REST simple
    2. Importer les données client de test
    3. Connecter l'API REST à la base de données client
    4. Ajouter une authentification à l'API REST

    Patrick et moi avons déjà les compétences requises pour les étapes 1 et 2, c'est donc un bon point de départ. Le prototype devrait être opérationnel d'ici la fin de la semaine.

    Ruby

    Aidez Ruby à gérer les activités nécessaires pour créer l'API REST pour Pet Theory.

    Tâche 1 : Activer les API Google

    Pour cet atelier, deux API ont été activées pour vous :

    Nom API
    Cloud Build cloudbuild.googleapis.com
    Cloud Run run.googleapis.com

    Tâche 2 : Développer l'API REST

    1. Activez votre projet :
    gcloud config set project $(gcloud projects list --format='value(PROJECT_ID)' --filter='qwiklabs-gcp')
    1. Clonez le dépôt "pet-theory" et accédez au code source :
    git clone https://github.com/rosera/pet-theory.git && cd pet-theory/lab08
    1. Utilisez votre éditeur de texte favori ou utilisez le bouton "Éditeur de code" dans le ruban Cloud Shell pour afficher les fichiers go.mod et go.sum.

    2. Créez le fichier main.go et ajoutez-y le contenu ci-dessous  :

    package main import ( "fmt" "log" "net/http" "os" ) func main() { port := os.Getenv("PORT") if port == "" { port = "8080" } http.HandleFunc("/v1/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "{status: 'running'}") }) log.Println("Pets REST API listening on port", port) if err := http.ListenAndServe(":"+port, nil); err != nil { log.Fatalf("Error launching Pets REST API server: %v", err) } } Remarque : Avec le code ci-dessus, vous créez un point de terminaison pour vérifier que le service est opérationnel. En ajoutant "/v1/" à l'URL du service, vous pouvez vérifier que l'application fonctionne comme prévu. Cloud Run déploie des conteneurs, vous devez donc fournir une définition de conteneur. Un fichier nommé "Dockerfile" indique à Cloud Run quelle version Go utiliser, quels fichiers inclure dans l'application et comment démarrer le code.
    1. Créez maintenant un fichier nommé Dockerfile et ajoutez-y ce qui suit :
    FROM gcr.io/distroless/base-debian12 WORKDIR /usr/src/app COPY server . CMD [ "/usr/src/app/server" ]

    Le fichier server est le binaire d'exécution construit à partir de main.go.

    1. Exécutez la commande suivante pour créer le binaire :
    go build -o server
    1. Après avoir exécuté la commande de compilation, assurez-vous que les fichiers "Dockerfile" et "server" nécessaires sont dans le même répertoire :
    ls -la . ├── Dockerfile ├── go.mod ├── go.sum ├── main.go └── server

    Pour la plupart des applications Cloud Run basées sur Go, il est possible d'utiliser un modèle de Dockerfile comme celui présenté ci-dessus sans le modifier.

    1. Déployez votre API REST simple en exécutant la commande suivante :
    gcloud builds submit \ --tag gcr.io/$GOOGLE_CLOUD_PROJECT/rest-api:0.1

    Cette commande construit un conteneur avec votre code et le place dans le Container Registry de votre projet. Pour voir le conteneur, cliquez sur le menu de navigation > Container Registry. Si rest-api n'apparaît pas, cliquez sur Actualiser.

    Container Registry

    Cliquez sur Vérifier ma progression pour vérifier que vous avez correctement effectué la tâche ci-dessus.

    Créer une image avec Cloud Build
    1. Une fois le conteneur créé, déployez-le :
    gcloud run deploy rest-api \ --image gcr.io/$GOOGLE_CLOUD_PROJECT/rest-api:0.1 \ --platform managed \ --region {{{ project_0.default_region | "Filled in at lab startup." }}} \ --allow-unauthenticated \ --max-instances=2
    1. Une fois le déploiement terminé, un message de ce type s'affiche :
    Service [rest-api] revision [rest-api-00001] has been deployed and is serving traffic at https://rest-api-[hash].a.run.app

    Cliquez sur Vérifier ma progression pour vérifier que vous avez correctement effectué la tâche ci-dessus.

    Service API REST déployé
    1. Cliquez sur l'URL du service à la fin de ce message pour l'ouvrir dans un nouvel onglet du navigateur. Ajoutez /v1/ à la fin de l'URL, puis appuyez sur Entrée.

    Le message suivant doit s'afficher :

    {&quot;status&quot; : &quot;running&quot;}

    L'API REST est opérationnelle. Avec le service de prototype disponible, dans la section suivante, l'API permettra de récupérer des informations sur le "client" à partir d'une base de données Firestore.

    Tâche 3 : Importer des données client de test

    Ruby

    Ruby, Consultante en logiciels

    Salut Patrick,

    As-tu encore les pseudo-données client que nous avions créées ? Nous en aurons besoin pour les tests.

    Te rappelles-tu comment configurer une base de données Firestore et importer des données ?

    Ruby

    Patrick

    Patrick, Administrateur informatique

    Bonjour Ruby,

    Oui, j'ai encore les données de test. Je vais les migrer aujourd'hui vers Firestore, et tu pourras les utiliser pour les tests.

    Patrick

    Ruby et Patrick ont déjà créé une base de données de test de 10 clients contenant des propositions de traitement pour le chat d'un client.

    Aidez Patrick à configurer la base de données Firestore et à importer les données de test des clients. Tout d'abord, activez Firestore dans votre projet.

    1. Revenez dans la console Cloud, puis cliquez sur le menu de navigation > Firestore.

    2. Cliquez sur le bouton Créer une base de données.

    3. Cliquez sur le bouton Mode natif, puis sur Continuer.

    4. Pour Type d'emplacement, sélectionnez Région.

    5. Sélectionnez la région dans la liste disponible et cliquez sur Créer une base de données.

    Attendez que la base de données soit créée avant de continuer.

    Cliquez sur Vérifier ma progression pour vérifier que vous avez correctement effectué la tâche ci-dessus.

    Base de données Firestore créée
    1. Migrez les fichiers d'importation vers un bucket Cloud Storage créé à votre intention :
    gsutil mb -c standard -l {{{ project_0.default_region | Region }}} gs://$GOOGLE_CLOUD_PROJECT-customer gsutil cp -r gs://spls/gsp645/2019-10-06T20:10:37_43617 gs://$GOOGLE_CLOUD_PROJECT-customer
    1. Importez maintenant ces données dans Firebase :
    gcloud beta firestore import gs://$GOOGLE_CLOUD_PROJECT-customer/2019-10-06T20:10:37_43617/

    Actualisez le navigateur de la console Cloud pour afficher les résultats Firestore.

    1. Dans Firestore, cliquez sur clients sous "Par défaut" (Racine). Les données des animaux importées devraient s'afficher. Parcourez-les pour vous en assurer. Si vous ne voyez aucune donnée, actualisez la page.

    Beau travail ! La base de données Firestore a bien été créée et contient les données de test.

    Tâche 4 : Connecter l'API REST à la base de données Firestore

    Ruby

    Ruby, Consultante en logiciels

    Bonjour Lily,

    Je voulais vous informer que Patrick et moi avons terminé les deux premières tâches de la liste.

    Je vais maintenant structurer l'API REST pour qu'elle puisse accéder aux données client dans Firestore.

    Ruby

    Lily

    Lily, fondatrice de Pet Theory

    Bonjour Ruby,

    Bravo, Ruby ! J'attends avec impatience la prochaine étape.

    Lily

    Dans cette section, vous allez aider Ruby à créer un autre point de terminaison dans l'API REST, qui se présentera comme suit :

    https://rest-api-[hash].a.run.app/v1/customer/22530

    Par exemple, cette URL doit renvoyer le montant total de tous les traitements proposés, acceptés et refusés pour le client associé à l'ID 22530, s'il existe dans la base de données Firestore :

    { "status": "success", "data": { "proposed": 1602, "approved": 585, "rejected": 489 } } Remarque : Si le client n'existe pas dans la base de données, le code d'état "404 Not Found" et un message d'erreur sont renvoyés à la place.

    Cette nouvelle fonctionnalité nécessite un package pour accéder à la base de données Firestore et un autre pour gérer le Cross-Origin Resource Sharing (CORS).

    1. Récupérez la valeur de la variable d'environnement $GOOGLE_CLOUD_PROJECT.
    echo $GOOGLE_CLOUD_PROJECT
    1. Ouvrez le fichier main.go existant dans le répertoire "pet-theory/lab08".
    Remarque : Mettez à jour le contenu du fichier main.go à l'aide de la valeur affichée pour $GOOGLE_CLOUD_PROJECT.
    1. Remplacez le contenu du fichier par le code ci-dessous, en vous assurant que PROJECT_ID est défini sur  :
    package main import ( "context" "encoding/json" "fmt" "log" "net/http" "os" "cloud.google.com/go/firestore" "github.com/gorilla/handlers" "github.com/gorilla/mux" "google.golang.org/api/iterator" ) var client *firestore.Client func main() { var err error ctx := context.Background() client, err = firestore.NewClient(ctx, "{{{ project_0.project_id | \"Filled in at lab startup\"}}}") if err != nil { log.Fatalf("Error initializing Cloud Firestore client: %v", err) } port := os.Getenv("PORT") if port == "" { port = "8080" } r := mux.NewRouter() r.HandleFunc("/v1/", rootHandler) r.HandleFunc("/v1/customer/{id}", customerHandler) log.Println("Pets REST API listening on port", port) cors := handlers.CORS( handlers.AllowedHeaders([]string{"X-Requested-With", "Authorization", "Origin"}), handlers.AllowedOrigins([]string{"https://storage.googleapis.com"}), handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "OPTIONS", "PATCH", "CONNECT"}), ) if err := http.ListenAndServe(":"+port, cors(r)); err != nil { log.Fatalf("Error launching Pets REST API server: %v", err) } }
    1. Ajoutez l'accès au gestionnaire en bas du fichier :
    func rootHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "{status: 'running'}") } func customerHandler(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] ctx := context.Background() customer, err := getCustomer(ctx, id) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": "fail", "data": '%s'}`, err) return } if customer == nil { w.WriteHeader(http.StatusNotFound) msg := fmt.Sprintf("`Customer \"%s\" not found`", id) fmt.Fprintf(w, fmt.Sprintf(`{"status": "fail", "data": {"title": %s}}`, msg)) return } amount, err := getAmounts(ctx, customer) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": "fail", "data": "Unable to fetch amounts: %s"}`, err) return } data, err := json.Marshal(amount) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": "fail", "data": "Unable to fetch amounts: %s"}`, err) return } fmt.Fprintf(w, fmt.Sprintf(`{"status": "success", "data": %s}`, data)) }
    1. Ajoutez l'accès à la base de données des clients au bas du fichier :
    type Customer struct { Email string `firestore:"email"` ID string `firestore:"id"` Name string `firestore:"name"` Phone string `firestore:"phone"` } func getCustomer(ctx context.Context, id string) (*Customer, error) { query := client.Collection("customers").Where("id", "==", id) iter := query.Documents(ctx) var c Customer for { doc, err := iter.Next() if err == iterator.Done { break } if err != nil { return nil, err } err = doc.DataTo(&c) if err != nil { return nil, err } } return &c, nil } func getAmounts(ctx context.Context, c *Customer) (map[string]int64, error) { if c == nil { return map[string]int64{}, fmt.Errorf("Customer should be non-nil: %v", c) } result := map[string]int64{ "proposed": 0, "approved": 0, "rejected": 0, } query := client.Collection(fmt.Sprintf("customers/%s/treatments", c.Email)) if query == nil { return map[string]int64{}, fmt.Errorf("Query is nil: %v", c) } iter := query.Documents(ctx) for { doc, err := iter.Next() if err == iterator.Done { break } if err != nil { return nil, err } treatment := doc.Data() result[treatment["status"].(string)] += treatment["cost"].(int64) } return result, nil }
    1. Enregistrez le fichier.

    Tâche 6 : Questionnaire

    Quelle fonction répond aux URL ayant le format /v1/customer/` ? getAmounts customerHandler Quelle instruction renvoie un résultat positif au client ? fmt.Fprintf(w, `{"status": "fail", "data": "Unable to fetch amounts: %s"} fmt.Fprintf(w, fmt.Sprintf(`{"status": "success", "data": %s} Quelles fonctions procèdent à la lecture dans la base de données Firestore ? customerHandler and getCustomer getCustomer and getAmounts

    Tâche 7 : Déployer une nouvelle révision

    1. Recompilez le code source :
    go build -o server
    1. Créez une image pour l'API REST :
    gcloud builds submit \ --tag gcr.io/$GOOGLE_CLOUD_PROJECT/rest-api:0.2

    Cliquez sur Vérifier ma progression pour valider l'objectif. Compiler la révision de l'image 0.2

    1. Déployez la nouvelle image :
    gcloud run deploy rest-api \ --image gcr.io/$GOOGLE_CLOUD_PROJECT/rest-api:0.2 \ --platform managed \ --region {{{ project_0.default_region | "Filled in at lab startup." }}} \ --allow-unauthenticated \ --max-instances=2 4. Une fois le déploiement terminé, un message semblable au précédent s'affiche. L'URL de l'API REST n'a pas changé lorsque vous avez déployé la nouvelle version : Service [rest-api] revision [rest-api-00002] has been deployed and is serving traffic at https://rest-api-[hash].a.run.app
    1. Revenez dans l'onglet du navigateur qui pointe déjà vers cette URL (avec /v1/ à la fin). Actualisez la page et vérifiez que le même message s'affiche, ce qui indique que l'API est toujours en cours d'exécution.

    {status&quot; : &quot;running&quot;}

    1. Ajoutez /customer/22530 à l'URL de l'application dans la barre d'adresse de votre navigateur. Vous devez obtenir cette réponse JSON qui affiche la somme totale des traitements proposés, acceptés et refusés pour ce client :

    {&quot;status&quot; : &quot;success&quot;, &quot;data&quot; :{&quot;proposed&quot; :1602, &quot;approved&quot; :585, &quot;rejected&quot; :489}}

    1. Voici quelques ID client supplémentaires que vous pouvez indiquer dans l'URL au lieu de 22530 :
    • 34216
    • 70156 (tous les montants doivent être nuls)
    • 12345 (le client/l'animal n'existe pas, un message d'erreur tel que Query is nil [La requête est nulle] devrait s'afficher).

    Vous avez créé une API REST évolutive, sans serveur, qui nécessite peu de maintenance et qui effectue des lectures à partir d'une base de données.

    Félicitations !

    Félicitations ! Dans cet atelier, vous avez aidé Ruby et Patrick à créer un prototype d'API REST pour Pet Theory. Vous avez créé une API REST qui se connecte à une base de données Firestore et l'avez déployée sur Cloud Run. Vous l'avez également testée pour vous assurer qu'elle fonctionne comme prévu.

    Formations et certifications Google Cloud

    Les formations et certifications Google Cloud vous aident à tirer pleinement parti des technologies Google Cloud. Nos cours portent sur les compétences techniques et les bonnes pratiques à suivre pour être rapidement opérationnel et poursuivre votre apprentissage. Nous proposons des formations pour tous les niveaux, à la demande, en salle et à distance, pour nous adapter aux emplois du temps de chacun. Les certifications vous permettent de valider et de démontrer vos compétences et votre expérience en matière de technologies Google Cloud.

    Dernière mise à jour du manuel : 6 mai 2024

    Dernier test de l'atelier : 6 mai 2024

    Copyright 2024 Google LLC Tous droits réservés. Google et le logo Google sont des marques de Google LLC. Tous les autres noms d'entreprises et de produits peuvent être des marques des entreprises auxquelles ils sont associés.

    Ce contenu n'est pas disponible pour le moment

    Nous vous préviendrons par e-mail lorsqu'il sera disponible

    Parfait !

    Nous vous contacterons par e-mail s'il devient disponible