Dans la deuxième partie de notre série d'articles «Rédaction d'un blog sur les microservices», nous avons décrit
la passerelle API .
Nous décrivons ici l'implémentation du microservice utilisateur.
Notre microservice devrait pouvoir:
- Consigner les appels de service et les états intermédiaires indiquant TraceId (le même émis par api-gw, voir la partie 2 «API Gateway» )
- Implémenter les fonctions de connexion (SignIN) et d'inscription (SignUp)
- Implémenter les fonctions CRUD (créer, lire, éditer, supprimer des enregistrements dans la base de données). Utilisez MongoDB comme base de données.
Tout d'abord, nous décrivons notre service dans le fichier proto (./services/user/protobuf/user.proto).
Spécifiez la syntaxe utilisée - proto3. Nous indiquons le nom du package protobuf, dans ce package le code généré automatiquement des parties serveur et client sera implémenté.
Nous importons la bibliothèque d'annotations google / api / annotations.proto, elle sera nécessaire pour décrire les directives de génération de l'API REST.
syntax = "proto3"; package protobuf; import "google/api/annotations.proto";
Description du service utilisateur, directement les interfaces (méthodes) qu'il devrait avoir. Par exemple, l'interface SignUp (inscription): elle reçoit un message SignUpRequest qui contient les attributs Username, Password, FirstName et LastName et répond avec un message SignUpResponse qui contient les attributs Slug (UserID), Username, Role. Toujours dans la description de l'interface, dans la section des options, spécifiez la directive post: "/ api / v1 / user / signup. Sur cette base, le générateur de code créera une interface REST qui recevra les requêtes POST sur http: {{api_gw_host}} / api / v1 / user / inscription.
Et il attendra la structure suivante dans le corps de la demande:
{ Username: 'username_value', Password: 'password_value', FirstName: 'firstname_value', LastName: 'lastname_value', }
Et en conséquence, en cas de succès, il donnera la structure:
{ Slug: 'user_id_value', Username: 'username_value', Role: 'role_value', }
Ou une erreur. Nous vous en dirons plus sur les erreurs un peu plus loin dans la section décrivant les fonctions qui implémentent les interfaces décrites dans le profil.
Les autres interfaces (SignIn, Create, Update, Delete, Get, Find) sont déclarées de la même manière.
Maintenant que nous avons un profil prédéfini. Nous allons dans le répertoire racine du projet et exécutons la commande sh ./bin/protogen.sh. Ce script générera le code principal.
Ensuite, allez dans le répertoire ./services/user et dans le fichier functions.go écrivez l'implémentation des interfaces déclarées.
Tout d'abord, nous implémentons un middleware. À chaque demande au service, nous extrayons les paramètres TraceId, UserId, UserRole du contexte de la demande et les écrivons dans le fichier journal. Ici, vous pouvez implémenter l'autorisation de demande.
Dans la méthode SignUp, nous déterminons la structure de réponse.
Ensuite, vérifiez les paramètres de la demande.
Et si tout va bien, remplissez la structure Utilisateur, écrivez dans la base de données et renvoyez la réponse.
user:=&User{ Username:in.Username, FirstName:in.FirstName, LastName:in.LastName, Password:getMD5(in.Password), } var slug string collection:= o.DbClient.Database("blog").Collection("users") insertResult, err := collection.InsertOne(context.TODO(), user) if err != nil { return out,err } if oid, ok := insertResult.InsertedID.(primitive.ObjectID); ok { slug=fmt.Sprintf("%s",oid.Hex()) }else { err:=app.ErrInsert return out,err } out.Slug=slug out.Username=in.Username out.Role=app.ROLE_USER return out,nil
Séparément, nous prêtons attention au retour d'erreur, par exemple:
err:=app.ErrInsert
Puisque finalement cette erreur reviendra à notre api-wg (dans sa partie REST) ​​et il serait cool de la convertir en un code de réponse HTTP standard. Afin de ne pas écrire un tas de code supplémentaire, vous ne devez pas utiliser l'erreur go standard, mais status.error du package google.golang.org/grpc/status.
Toutes les erreurs typiques du microservice Utilisateur et la façon dont elles sont converties en codes de réponse HTTP sont décrites dans le fichier. / Services / user / app / errors.go.
package app import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" )
Et la dernière chose que je voudrais dire sur le microservice utilisateur est la façon dont il démarre et se connecte à la base de données. Ces opérations sont effectuées dans le fichier ./services/user/main.go.
Lancement du service:
lis,err:= net.Listen("tcp", fmt.Sprintf(":%s", Port)) if err != nil { log.Fatalf("failed to listen: %v", err) } grpcServer:= grpc.NewServer( grpc.UnaryInterceptor(protobuf.AccessLogInterceptor), ) s:=&protobuf.Server{} …
Connexion à la base de données (main.go):
Implémentation de la fonction DbConnect (./services/user/functions.go):