From 73ce65948b25d513284e99e3857a1f1a80235c36 Mon Sep 17 00:00:00 2001 From: Edem Date: Sat, 28 May 2022 15:16:12 +0000 Subject: [PATCH 1/5] updated --- cmd/server/main.go | 3 +++ controllers/auth.controller.go | 4 +--- controllers/post.controller.go | 4 ++++ controllers/user.controller.go | 4 ++-- gapi/rpc_signup_user.go | 2 +- models/user.model.go | 8 ++++---- services/auth.service.go | 4 ++-- services/auth.service.impl.go | 6 +++--- services/post.service.impl.go | 15 ++++----------- services/user.service.go | 6 +++--- services/user.service.impl.go | 31 +++++++++++++++---------------- utils/email.go | 2 +- 12 files changed, 43 insertions(+), 46 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index 3a726dd..561f788 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -38,6 +38,7 @@ var ( AuthController controllers.AuthController AuthRouteController routes.AuthRouteController + // 👇 Add the Post Service, Controllers and Routes postService services.PostService PostController controllers.PostController postCollection *mongo.Collection @@ -92,6 +93,7 @@ func init() { UserController = controllers.NewUserController(userService) UserRouteController = routes.NewRouteUserController(UserController) + // 👇 Add the Post Service, Controllers and Routes postCollection = mongoclient.Database("golang_mongodb").Collection("posts") postService = services.NewPostService(postCollection, ctx) PostController = controllers.NewPostController(postService) @@ -164,6 +166,7 @@ func startGinServer(config config.Config) { AuthRouteController.AuthRoute(router, userService) UserRouteController.UserRoute(router, userService) + // 👇 Evoke the PostRoute PostRouteController.PostRoute(router) log.Fatal(server.Run(":" + config.Port)) } diff --git a/controllers/auth.controller.go b/controllers/auth.controller.go index ea3c8c2..34f77d7 100644 --- a/controllers/auth.controller.go +++ b/controllers/auth.controller.go @@ -63,7 +63,7 @@ func (ac *AuthController) SignUpUser(ctx *gin.Context) { verificationCode := utils.Encode(code) - updateData := &models.UpdateInput{ + updateData := &models.UserUpdateInput{ VerificationCode: verificationCode, } @@ -205,8 +205,6 @@ func (ac *AuthController) VerifyEmail(ctx *gin.Context) { return } - fmt.Println(result) - ctx.JSON(http.StatusOK, gin.H{"status": "success", "message": "Email verified successfully"}) } diff --git a/controllers/post.controller.go b/controllers/post.controller.go index 0ce8253..8362bce 100644 --- a/controllers/post.controller.go +++ b/controllers/post.controller.go @@ -69,6 +69,10 @@ func (pc *PostController) FindPostById(ctx *gin.Context) { post, err := pc.postService.FindPostById(postId) if err != nil { + if strings.Contains(err.Error(), "Id exists") { + ctx.JSON(http.StatusNotFound, gin.H{"status": "fail", "message": err.Error()}) + return + } ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) return } diff --git a/controllers/user.controller.go b/controllers/user.controller.go index f57fd3b..293a453 100644 --- a/controllers/user.controller.go +++ b/controllers/user.controller.go @@ -17,7 +17,7 @@ func NewUserController(userService services.UserService) UserController { } func (uc *UserController) GetMe(ctx *gin.Context) { - currentUser := ctx.MustGet("currentUser").(*models.DBResponse) + currentUser := ctx.MustGet("currentUser").(*models.UserDBResponse) - ctx.JSON(http.StatusOK, gin.H{"status": "success", "data": gin.H{"user": models.FilteredResponse(currentUser)}}) + ctx.JSON(http.StatusOK, gin.H{"status": "success", "data": gin.H{"user": models.FilteredUserResponse(currentUser)}}) } diff --git a/gapi/rpc_signup_user.go b/gapi/rpc_signup_user.go index 1682d7b..25c64f5 100644 --- a/gapi/rpc_signup_user.go +++ b/gapi/rpc_signup_user.go @@ -39,7 +39,7 @@ func (authServer *AuthServer) SignUpUser(ctx context.Context, req *pb.SignUpUser verificationCode := utils.Encode(code) - updateData := &models.UpdateInput{ + updateData := &models.UserUpdateInput{ VerificationCode: verificationCode, } diff --git a/models/user.model.go b/models/user.model.go index 690f287..709db99 100644 --- a/models/user.model.go +++ b/models/user.model.go @@ -27,8 +27,8 @@ type SignInInput struct { Password string `json:"password" bson:"password" binding:"required"` } -// 👈 DBResponse struct -type DBResponse struct { +// 👈 UserDBResponse struct +type UserDBResponse struct { ID primitive.ObjectID `json:"id" bson:"_id"` Name string `json:"name" bson:"name"` Email string `json:"email" bson:"email"` @@ -43,7 +43,7 @@ type DBResponse struct { UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` } -type UpdateInput struct { +type UserUpdateInput struct { Name string `json:"name,omitempty" bson:"name,omitempty"` Email string `json:"email,omitempty" bson:"email,omitempty"` Password string `json:"password,omitempty" bson:"password,omitempty"` @@ -77,7 +77,7 @@ type ResetPasswordInput struct { PasswordConfirm string `json:"passwordConfirm,omitempty" bson:"passwordConfirm,omitempty"` } -func FilteredResponse(user *DBResponse) UserResponse { +func FilteredUserResponse(user *UserDBResponse) UserResponse { return UserResponse{ ID: user.ID, Email: user.Email, diff --git a/services/auth.service.go b/services/auth.service.go index eaa9afe..42b39d3 100644 --- a/services/auth.service.go +++ b/services/auth.service.go @@ -3,6 +3,6 @@ package services import "github.com/wpcodevo/golang-mongodb/models" type AuthService interface { - SignUpUser(*models.SignUpInput) (*models.DBResponse, error) - SignInUser(*models.SignInInput) (*models.DBResponse, error) + SignUpUser(*models.SignUpInput) (*models.UserDBResponse, error) + SignInUser(*models.SignInInput) (*models.UserDBResponse, error) } diff --git a/services/auth.service.impl.go b/services/auth.service.impl.go index d144fb4..98e6078 100644 --- a/services/auth.service.impl.go +++ b/services/auth.service.impl.go @@ -22,7 +22,7 @@ func NewAuthService(collection *mongo.Collection, ctx context.Context) AuthServi return &AuthServiceImpl{collection, ctx} } -func (uc *AuthServiceImpl) SignUpUser(user *models.SignUpInput) (*models.DBResponse, error) { +func (uc *AuthServiceImpl) SignUpUser(user *models.SignUpInput) (*models.UserDBResponse, error) { user.CreatedAt = time.Now() user.UpdatedAt = user.CreatedAt user.Email = strings.ToLower(user.Email) @@ -50,7 +50,7 @@ func (uc *AuthServiceImpl) SignUpUser(user *models.SignUpInput) (*models.DBRespo return nil, errors.New("could not create index for email") } - var newUser *models.DBResponse + var newUser *models.UserDBResponse query := bson.M{"_id": res.InsertedID} err = uc.collection.FindOne(uc.ctx, query).Decode(&newUser) @@ -61,6 +61,6 @@ func (uc *AuthServiceImpl) SignUpUser(user *models.SignUpInput) (*models.DBRespo return newUser, nil } -func (uc *AuthServiceImpl) SignInUser(*models.SignInInput) (*models.DBResponse, error) { +func (uc *AuthServiceImpl) SignInUser(*models.SignInInput) (*models.UserDBResponse, error) { return nil, nil } diff --git a/services/post.service.impl.go b/services/post.service.impl.go index 47d1563..2d2450e 100644 --- a/services/post.service.impl.go +++ b/services/post.service.impl.go @@ -61,19 +61,12 @@ func (p *PostServiceImpl) UpdatePost(id string, data *models.UpdatePost) (*model obId, _ := primitive.ObjectIDFromHex(id) query := bson.D{{Key: "_id", Value: obId}} update := bson.D{{Key: "$set", Value: doc}} - res, err := p.postCollection.UpdateOne(p.ctx, query, update) - if err != nil { - return nil, err - } - - if res.MatchedCount == 0 { - return nil, errors.New("no post with that Id exists") - } + res := p.postCollection.FindOneAndUpdate(p.ctx, query, update, options.FindOneAndUpdate().SetReturnDocument(1)) var updatedPost *models.DBPost - if err = p.postCollection.FindOne(p.ctx, query).Decode(&updatedPost); err != nil { - return nil, err + if err := res.Decode(&updatedPost); err != nil { + return nil, errors.New("no post with that Id exists") } return updatedPost, nil @@ -115,7 +108,7 @@ func (p *PostServiceImpl) FindPosts(page int, limit int) ([]*models.DBPost, erro var posts []*models.DBPost - if cursor.Next(p.ctx) { + for cursor.Next(p.ctx) { post := &models.DBPost{} err := cursor.Decode(post) diff --git a/services/user.service.go b/services/user.service.go index cc428ad..60e3189 100644 --- a/services/user.service.go +++ b/services/user.service.go @@ -3,7 +3,7 @@ package services import "github.com/wpcodevo/golang-mongodb/models" type UserService interface { - FindUserById(id string) (*models.DBResponse, error) - FindUserByEmail(email string) (*models.DBResponse, error) - UpdateUserById(id string, data *models.UpdateInput) (*models.DBResponse, error) + FindUserById(id string) (*models.UserDBResponse, error) + FindUserByEmail(email string) (*models.UserDBResponse, error) + UpdateUserById(id string, data *models.UserUpdateInput) (*models.UserDBResponse, error) } diff --git a/services/user.service.impl.go b/services/user.service.impl.go index 081035b..609416a 100644 --- a/services/user.service.impl.go +++ b/services/user.service.impl.go @@ -2,7 +2,7 @@ package services import ( "context" - "fmt" + "errors" "strings" "github.com/wpcodevo/golang-mongodb/models" @@ -10,6 +10,7 @@ import ( "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" ) type UserServiceImpl struct { @@ -21,17 +22,17 @@ func NewUserServiceImpl(collection *mongo.Collection, ctx context.Context) UserS return &UserServiceImpl{collection, ctx} } -func (us *UserServiceImpl) FindUserById(id string) (*models.DBResponse, error) { +func (us *UserServiceImpl) FindUserById(id string) (*models.UserDBResponse, error) { oid, _ := primitive.ObjectIDFromHex(id) - var user *models.DBResponse + var user *models.UserDBResponse query := bson.M{"_id": oid} err := us.collection.FindOne(us.ctx, query).Decode(&user) if err != nil { if err == mongo.ErrNoDocuments { - return &models.DBResponse{}, err + return &models.UserDBResponse{}, err } return nil, err } @@ -39,15 +40,15 @@ func (us *UserServiceImpl) FindUserById(id string) (*models.DBResponse, error) { return user, nil } -func (us *UserServiceImpl) FindUserByEmail(email string) (*models.DBResponse, error) { - var user *models.DBResponse +func (us *UserServiceImpl) FindUserByEmail(email string) (*models.UserDBResponse, error) { + var user *models.UserDBResponse query := bson.M{"email": strings.ToLower(email)} err := us.collection.FindOne(us.ctx, query).Decode(&user) if err != nil { if err == mongo.ErrNoDocuments { - return &models.DBResponse{}, err + return &models.UserDBResponse{}, err } return nil, err } @@ -55,24 +56,22 @@ func (us *UserServiceImpl) FindUserByEmail(email string) (*models.DBResponse, er return user, nil } -func (uc *UserServiceImpl) UpdateUserById(id string, data *models.UpdateInput) (*models.DBResponse, error) { +func (uc *UserServiceImpl) UpdateUserById(id string, data *models.UserUpdateInput) (*models.UserDBResponse, error) { doc, err := utils.ToDoc(data) if err != nil { - return &models.DBResponse{}, err + return &models.UserDBResponse{}, err } - fmt.Println(data) - obId, _ := primitive.ObjectIDFromHex(id) query := bson.D{{Key: "_id", Value: obId}} update := bson.D{{Key: "$set", Value: doc}} - result, err := uc.collection.UpdateOne(uc.ctx, query, update) + result := uc.collection.FindOneAndUpdate(uc.ctx, query, update, options.FindOneAndUpdate().SetReturnDocument(1)) - fmt.Print(result.ModifiedCount) - if err != nil { - return &models.DBResponse{}, err + var updatedUser *models.UserDBResponse + if err := result.Decode(&updatedUser); err != nil { + return nil, errors.New("no user with that id exists") } - return &models.DBResponse{}, nil + return updatedUser, nil } diff --git a/utils/email.go b/utils/email.go index 4fabae8..d20002d 100644 --- a/utils/email.go +++ b/utils/email.go @@ -44,7 +44,7 @@ func ParseTemplateDir(dir string) (*template.Template, error) { return template.ParseFiles(paths...) } -func SendEmail(user *models.DBResponse, data *EmailData, templateName string) error { +func SendEmail(user *models.UserDBResponse, data *EmailData, templateName string) error { config, err := config.LoadConfig(".") if err != nil { From 36d736dcf10ef50da37c05ff74fd4850021e50b6 Mon Sep 17 00:00:00 2001 From: Edem Date: Sat, 28 May 2022 16:19:04 +0000 Subject: [PATCH 2/5] updated --- services/post.service.impl.go | 8 ++++++++ tmp/build-errors.log | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/services/post.service.impl.go b/services/post.service.impl.go index 2d2450e..7881fd1 100644 --- a/services/post.service.impl.go +++ b/services/post.service.impl.go @@ -91,6 +91,14 @@ func (p *PostServiceImpl) FindPostById(id string) (*models.DBPost, error) { } func (p *PostServiceImpl) FindPosts(page int, limit int) ([]*models.DBPost, error) { + if page == 0 { + page = 1 + } + + if limit == 0 { + limit = 10 + } + skip := (page - 1) * limit opt := options.FindOptions{} diff --git a/tmp/build-errors.log b/tmp/build-errors.log index 85600e2..8cac00d 100644 --- a/tmp/build-errors.log +++ b/tmp/build-errors.log @@ -1 +1 @@ -exit status 1exit status 0xc000013aexit status 1exit status 1exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 1exit status 1exit status 2exit status 1 \ No newline at end of file +exit status 1exit status 0xc000013aexit status 1exit status 1exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 1exit status 1exit status 2exit status 1exit status 0xc000013a \ No newline at end of file From aeb4b326fbfacdaa1ab748fcb34f9bad561a0fba Mon Sep 17 00:00:00 2001 From: Edem Date: Sat, 28 May 2022 16:21:05 +0000 Subject: [PATCH 3/5] updated --- readMe.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/readMe.md b/readMe.md index 56a6138..da96030 100644 --- a/readMe.md +++ b/readMe.md @@ -1,4 +1,4 @@ -# API with Golang + MongoDB + Redis + Gin Gonic +# CRUD RESTful API with Golang + MongoDB + Redis + Gin Gonic ### 1. API with Golang + MongoDB + Redis + Gin Gonic: Project Setup @@ -19,3 +19,11 @@ ### 5. Build Golang gRPC Server and Client: SignUp User & Verify Email [Build Golang gRPC Server and Client: SignUp User & Verify Email](https://codevoweb.com/golang-grpc-server-and-client-signup-user-verify-email) + +### 6. Build Golang gRPC Server and Client: Access & Refresh Tokens + +[Build Golang gRPC Server and Client: Access & Refresh Tokens](https://codevoweb.com/golang-grpc-server-and-client-access-refresh-tokens) + +### 7. Build CRUD RESTful API Server with Golang, Gin, and MongoDB + +[Build CRUD RESTful API Server with Golang, Gin, and MongoDB](https://codevoweb.com/crud-restful-api-server-with-golang-and-mongodb) From f49491e6f607a742be06d3d718bb6c05e4d80b2d Mon Sep 17 00:00:00 2001 From: Edem Date: Wed, 1 Jun 2022 22:51:20 +0000 Subject: [PATCH 4/5] updated --- readMe.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readMe.md b/readMe.md index da96030..224cc58 100644 --- a/readMe.md +++ b/readMe.md @@ -27,3 +27,7 @@ ### 7. Build CRUD RESTful API Server with Golang, Gin, and MongoDB [Build CRUD RESTful API Server with Golang, Gin, and MongoDB](https://codevoweb.com/crud-restful-api-server-with-golang-and-mongodb) + +### 8. Build CRUD gRPC Server API & Client with Golang and MongoDB + +[Build CRUD gRPC Server API & Client with Golang and MongoDB](https://codevoweb.com/crud-grpc-server-api-client-with-golang-and-mongodb) From 328068cc122d74f2d25d8872815b48917d19bcf3 Mon Sep 17 00:00:00 2001 From: CODEVO Date: Sun, 2 Oct 2022 18:40:04 +0000 Subject: [PATCH 5/5] Update readMe.md --- readMe.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/readMe.md b/readMe.md index 224cc58..30863fe 100644 --- a/readMe.md +++ b/readMe.md @@ -1,4 +1,34 @@ -# CRUD RESTful API with Golang + MongoDB + Redis + Gin Gonic +# Build CRUD RESTful API Server with Golang, Gin, and MongoDB + +In this article, you'll learn how to build a CRUD RESTful API server with Golang, Gin Gonic, MongoDB-Go-driver, Docker, and Docker-compose. + +![Build CRUD RESTful API Server with Golang, Gin, and MongoDB](https://codevoweb.com/wp-content/uploads/2022/05/Build-CRUD-RESTful-API-Server-with-Golang-Gin-and-MongoDB.webp) + +## Topics Covered + +- Golang, Gin Gonic, MongoDB CRUD RESTful API Overview +- Create the Models with Structs +- Create the Service Interface +- Create Methods to Implement the Interface + - Initialize the Service Struct + - Define a Service to Create a Post + - Define a Service to Update Post + - Define a Service to Delete Post + - Define a Service to Get Single Post + - Define a Service to Get All Posts +- Create Controllers to Perform the CRUD Operations + - Initialize the Controller Struct + - Define a Controller to Create a Post + - Define a Controller to Update a Post + - Define a Controller to Delete a Post + - Define a Controller to Get a Single Post + - Define a Controller to Get All Posts +- Create the Routes for the Controllers +- Initialize the Constructors and Start the Gin Server + +Read the entire article here: [https://codevoweb.com/crud-restful-api-server-with-golang-and-mongodb](https://codevoweb.com/crud-restful-api-server-with-golang-and-mongodb) + +Articles in this series: ### 1. API with Golang + MongoDB + Redis + Gin Gonic: Project Setup