How I can connect Cloud Firestore with Gin framework? using main.go and route.go. I have created a project on cloud firestore with the collection "users"
This is my main.go
package main
import (
"context"
"log"
"project/routes"
"github.com/gin-gonic/gin"
firebase "firebase.google.com/go"
"google.golang.org/api/option"
)
const (
projectID string = "ProjectID"
collectionName string = "users"
)
func main() {
// get the db connection and check for error
app, err := connectDB()
if err != nil {
return
}
router := gin.Default()
// all router have access to the db
router.Use(dbMiddleware(*app))
usersGroup := router.Group("users")
{
usersGroup.POST("register", routes.UsersRegister)
}
router.Run()
}
//connecting the api to the firestore
func connectDB() (c *firebase.App, err error) {
ctx := context.Background()
opt := option.WithCredentialsFile("path/to/file.json")
app, err := firebase.NewApp(ctx, nil, opt)
if err != nil {
log.Fatalln(err)
return nil, err
}
client, err := app.Firestore(ctx)
if err != nil {
log.Fatalln(err)
return nil, err
}
defer client.Close()
return app, err
}
// create a middleware that attach the db connection to the context
func dbMiddleware(app firebase.App) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set("db", app)
c.Next()
}
}
This is routes/users.go
package routes
import (
"fmt"
"project/models"
"net/http"
firebase "firebase.google.com/go"
"github.com/gin-gonic/gin"
)
func UsersRegister(c *gin.Context) {
user := models.User{}
err := c.ShouldBindJSON(&user)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
db, _ := c.Get("db")
app := db.(firebase.App)
err = user.Register(&app)
if err != nil {
fmt.Println("Error in user.Register()")
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"user_id": user.ID,
})
}
This is models/users.go
package models
import (
"context"
"fmt"
"log"
"strings"
"time"
"cloud.google.com/go/firestore"
firebase "firebase.google.com/go"
"github.com/gofrs/uuid"
"golang.org/x/crypto/bcrypt"
)
const (
projectID string = "ProjectId"
collectionName string = "users"
)
var client *firestore.Client
type User struct {
ID uuid.UUID `json:"id"`
CreatedAt time.Time `json:"_"`
UpdatedAt time.Time `json:"_"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
PasswordHash string `json:"-"`
Password string `json:"password"`
PasswordConfirm string `json:"password_confirm"`
}
func (u *User) Register(app *firebase.App) error {
if len(u.Password) < 4 || len(u.PasswordConfirm) < 4 {
return fmt.Errorf("Password must be at least 4 characters long.")
}
if u.Password != u.PasswordConfirm {
return fmt.Errorf("Passwords do not match.")
}
if len(u.Email) < 4 {
return fmt.Errorf("Email must be at least 4 characters long.")
}
u.Email = strings.ToLower(u.Email)
//TO DO check if the email does exist in the db
// using bcrypt library to hash the password
pwdHash, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
if err != nil {
return fmt.Errorf("There was an error creating your account.")
}
u.PasswordHash = string(pwdHash)
now := time.Now()
ctx := context.Background()
defer client.Close()
if err != nil {
log.Fatalf(" Failed to create DB")
return nil
}
var user User
_, _, err = client.Collection(collectionName).Add(ctx, map[string]interface{}{
"ID": user.ID,
"FirstName ": user.FirstName,
"LastName": user.LastName,
"Email": user.Email,
"PasswordHash": user.PasswordHash,
"CreatedAt": now,
"UpdatedAt": now,
})
if err != nil {
log.Fatalf(" Failed to add new user")
return nil
}
return err
}
The server run but when I run postman to post to http://localhost:8080/users/register/
I got this on my terminal.
panic recovered:
POST /users/register HTTP/1.1
runtime error: invalid memory address or nil pointer dereference
I have been trying to connect the to firestore for the last 5 days but I have a problem somewhere. Thanks for your help in advance.