Skip to content

Commit

Permalink
Adding custom validators, better example of operation results for SQL…
Browse files Browse the repository at this point in the history
…, best practices and cleanups
  • Loading branch information
Massad committed Jun 17, 2021
1 parent 52c3248 commit 35a367a
Show file tree
Hide file tree
Showing 13 changed files with 440 additions and 122 deletions.
1 change: 1 addition & 0 deletions .env_rename_me
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
ENV=LOCAL
PORT=9000
SSL=TRUE
API_VERSION=2.0
DB_USER="postgres"
DB_PASS="postgres"
DB_NAME="golang_gin_db"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The fastest way to deploy a restful api's with [Gin Framework](https://gin-gonic
- [jwt-go](https://github.com/dgrijalva/jwt-go): JSON Web Tokens (JWT) as middleware
- [go-redis](https://github.com/go-redis/redis): Redis support for Go
- Go Modules
- Built-in custom validators
- Built-in **CORS Middleware**
- Built-in **RequestID Middleware**
- Feature **PostgreSQL 12** with JSON/JSONB queries & trigger functions
Expand Down
130 changes: 67 additions & 63 deletions controllers/article.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,106 +15,110 @@ import (
type ArticleController struct{}

var articleModel = new(models.ArticleModel)
var articleForm = new(forms.ArticleForm)

//Create ...
func (ctrl ArticleController) Create(c *gin.Context) {
if userID := getUserID(c); userID != 0 {
userID := getUserID(c)

var articleForm forms.ArticleForm
var form forms.CreateAtricleForm

if c.ShouldBindJSON(&articleForm) != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"message": "Invalid form"})
return
}

articleID, err := articleModel.Create(userID, articleForm)

if articleID == 0 && err != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"message": "Article could not be created", "error": err.Error()})
return
}
if validationErr := c.ShouldBindJSON(&form); validationErr != nil {
message := articleForm.Create(validationErr)
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"message": message})
return
}

c.JSON(http.StatusOK, gin.H{"message": "Article created", "id": articleID})
id, err := articleModel.Create(userID, form)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"message": "Article could not be created"})
return
}

c.JSON(http.StatusOK, gin.H{"message": "Article created", "id": id})
}

//All ...
func (ctrl ArticleController) All(c *gin.Context) {
if userID := getUserID(c); userID != 0 {
userID := getUserID(c)

results, err := articleModel.All(userID)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"Message": "Could not get articles", "error": err.Error()})
return
}

c.JSON(http.StatusOK, gin.H{"results": results})
results, err := articleModel.All(userID)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"Message": "Could not get articles"})
return
}

c.JSON(http.StatusOK, gin.H{"results": results})
}

//One ...
func (ctrl ArticleController) One(c *gin.Context) {
if userID := getUserID(c); userID != 0 {
userID := getUserID(c)

id := c.Param("id")
if id, err := strconv.ParseInt(id, 10, 64); err == nil {
id := c.Param("id")

data, err := articleModel.One(userID, id)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"Message": "Article not found", "error": err.Error()})
return
}
getID, err := strconv.ParseInt(id, 10, 64)
if getID == 0 || err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"Message": "Invalid parameter"})
return
}

c.JSON(http.StatusOK, gin.H{"data": data})
} else {
c.JSON(http.StatusNotFound, gin.H{"Message": "Invalid parameter"})
}
data, err := articleModel.One(userID, getID)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"Message": "Article not found"})
return
}

c.JSON(http.StatusOK, gin.H{"data": data})
}

//Update ...
func (ctrl ArticleController) Update(c *gin.Context) {
if userID := getUserID(c); userID != 0 {
userID := getUserID(c)

id := c.Param("id")
if id, err := strconv.ParseInt(id, 10, 64); err == nil {
id := c.Param("id")

var articleForm forms.ArticleForm
getID, err := strconv.ParseInt(id, 10, 64)
if getID == 0 || err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"Message": "Invalid parameter"})
return
}

if c.ShouldBindJSON(&articleForm) != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"message": "Invalid form"})
return
}
var form forms.CreateAtricleForm

err := articleModel.Update(userID, id, articleForm)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"Message": "Article could not be updated", "error": err.Error()})
return
}
if validationErr := c.ShouldBindJSON(&form); validationErr != nil {
message := articleForm.Create(validationErr)
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"message": message})
return
}

c.JSON(http.StatusOK, gin.H{"message": "Article updated"})
} else {
c.JSON(http.StatusNotFound, gin.H{"Message": "Invalid parameter", "error": err.Error()})
}
err = articleModel.Update(userID, getID, form)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"Message": "Article could not be updated"})
return
}

c.JSON(http.StatusOK, gin.H{"message": "Article updated"})
}

//Delete ...
func (ctrl ArticleController) Delete(c *gin.Context) {
if userID := getUserID(c); userID != 0 {
userID := getUserID(c)

id := c.Param("id")
if id, err := strconv.ParseInt(id, 10, 64); err == nil {
id := c.Param("id")

err := articleModel.Delete(userID, id)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"Message": "Article could not be deleted", "error": err.Error()})
return
}
getID, err := strconv.ParseInt(id, 10, 64)
if getID == 0 || err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"Message": "Invalid parameter"})
return
}

c.JSON(http.StatusOK, gin.H{"message": "Article deleted"})
} else {
c.JSON(http.StatusNotFound, gin.H{"Message": "Invalid parameter"})
}
err = articleModel.Delete(userID, getID)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"Message": "Article could not be deleted"})
return
}

c.JSON(http.StatusOK, gin.H{"message": "Article deleted"})

}
27 changes: 12 additions & 15 deletions controllers/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
type UserController struct{}

var userModel = new(models.UserModel)
var userForm = new(forms.UserForm)

//getUserID ...
func getUserID(c *gin.Context) (userID int64) {
Expand All @@ -24,42 +25,38 @@ func getUserID(c *gin.Context) (userID int64) {
func (ctrl UserController) Login(c *gin.Context) {
var loginForm forms.LoginForm

if c.ShouldBindJSON(&loginForm) != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"message": "Invalid form"})
if validationErr := c.ShouldBindJSON(&loginForm); validationErr != nil {
message := userForm.Login(validationErr)
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"message": message})
return
}

user, token, err := userModel.Login(loginForm)
if err == nil {
c.JSON(http.StatusOK, gin.H{"message": "User signed in", "user": user, "token": token})
} else {
c.JSON(http.StatusNotAcceptable, gin.H{"message": "Invalid login details", "error": err.Error()})
if err != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"message": "Invalid login details"})
return
}

c.JSON(http.StatusOK, gin.H{"message": "Successfully logged in", "user": user, "token": token})
}

//Register ...
func (ctrl UserController) Register(c *gin.Context) {
var registerForm forms.RegisterForm

if c.ShouldBindJSON(&registerForm) != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"message": "Invalid form"})
if validationErr := c.ShouldBindJSON(&registerForm); validationErr != nil {
message := userForm.Register(validationErr)
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"message": message})
return
}

user, err := userModel.Register(registerForm)

if err != nil {
c.AbortWithStatusJSON(http.StatusNotAcceptable, gin.H{"message": err.Error()})
return
}

if user.ID > 0 {
c.JSON(http.StatusOK, gin.H{"message": "Successfully registered", "user": user})
} else {
c.JSON(http.StatusNotAcceptable, gin.H{"message": "Could not register this user", "error": err.Error()})
}

c.JSON(http.StatusOK, gin.H{"message": "Successfully registered", "user": user})
}

//Logout ...
Expand Down
20 changes: 15 additions & 5 deletions db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"log"
"os"
"strconv"

"github.com/go-gorp/gorp"
_redis "github.com/go-redis/redis/v7"
Expand Down Expand Up @@ -38,9 +37,11 @@ func ConnectDB(dataSourceName string) (*gorp.DbMap, error) {
if err != nil {
return nil, err
}

if err = db.Ping(); err != nil {
return nil, err
}

dbmap := &gorp.DbMap{Db: db, Dialect: gorp.PostgresDialect{}}
//dbmap.TraceOn("[gorp]", log.New(os.Stdout, "golang-gin:", log.Lmicroseconds)) //Trace database requests
return dbmap, nil
Expand All @@ -55,18 +56,27 @@ func GetDB() *gorp.DbMap {
var RedisClient *_redis.Client

//InitRedis ...
func InitRedis(params ...string) {
func InitRedis(selectDB ...int) {

var redisHost = os.Getenv("REDIS_HOST")
var redisPassword = os.Getenv("REDIS_PASSWORD")

db, _ := strconv.Atoi(params[0])

RedisClient = _redis.NewClient(&_redis.Options{
Addr: redisHost,
Password: redisPassword,
DB: db,
DB: selectDB[0],
// DialTimeout: 10 * time.Second,
// ReadTimeout: 30 * time.Second,
// WriteTimeout: 30 * time.Second,
// PoolSize: 10,
// PoolTimeout: 30 * time.Second,
// IdleTimeout: 500 * time.Millisecond,
// IdleCheckFrequency: 500 * time.Millisecond,
// TLSConfig: &tls.Config{
// InsecureSkipVerify: true,
// },
})

}

//GetRedis ...
Expand Down
Loading

0 comments on commit 35a367a

Please sign in to comment.