Skip to content

Commit

Permalink
Merge pull request #26 from mecitsemerci/develop
Browse files Browse the repository at this point in the history
Add logger and error wrapper
  • Loading branch information
mecitsemerci authored Sep 16, 2021
2 parents 2468c14 + 5d358c2 commit 77cda0a
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 17 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ JAEGER_SAMPLER_PARAM=1
JAEGER_SAMPLER_TYPE=probabilistic
JAEGER_SERVICE_NAME=go-todo-app
JAEGER_DISABLED=false
GIN_MODE=debug
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@
This repository is a todo sample go and angular web project built according to Clean Architecture.

## Technologies
* Go Web Framework (gin-gonic)
* Containerize (Docker)
* Swagger (swaggo)
* Go Web Framework ([gin-gonic](https://github.com/gin-gonic/gin))
* Containerize ([docker](https://www.docker.com/))
* Swagger ([swaggo](https://github.com/swaggo/swag))
* Database
* Mongodb (default)
* Redis
* Dependency Injection (wire by google)
* Unit/Integration Tests (testify)
* Tracing (opentracing)
* WebUI (Angular 11)
* [MongoDB](https://www.mongodb.com/) (default)
* [Redis](https://redis.io/)
* Dependency Injection ([google wire](https://github.com/google/wire))
* Unit/Integration Tests ([testify](https://github.com/stretchr/testify))
* Tracing ([opentracing](https://github.com/opentracing/opentracing-go))
* Logger ([logrus](https://github.com/sirupsen/logrus))
* Error Wrapper ([pkg errors](https://github.com/pkg/errors))
* WebUI ([Angular 11](https://angular.io/))

### Web UI Preview
![GitHub Logo](https://github.com/mecitsemerci/blog/blob/master/src/images/angular_ui.gif?raw=true)
Expand Down
1 change: 1 addition & 0 deletions docker-compose.redis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ services:
- JAEGER_SAMPLER_PARAM=1
- JAEGER_SAMPLER_TYPE=probabilistic
- JAEGER_SERVICE_NAME=go-todo-app
- GIN_MODE=debug
ports:
- "8080:8080" # Forward the exposed port 8080 on the container to port 8080 on the host machine
restart: unless-stopped
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ services:
- JAEGER_SAMPLER_PARAM=1
- JAEGER_SAMPLER_TYPE=probabilistic
- JAEGER_SERVICE_NAME=go-todo-app
- GIN_MODE=debug
ports:
- "8080:8080" # Forward the exposed port 8080 on the container to port 8080 on the host machine
restart: unless-stopped
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ require (
github.com/google/uuid v1.2.0
github.com/google/wire v0.5.0
github.com/opentracing/opentracing-go v1.2.0
github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/stretchr/objx v0.2.0 // indirect
github.com/stretchr/testify v1.7.0
github.com/swaggo/gin-swagger v1.2.0
Expand All @@ -22,4 +24,5 @@ require (
github.com/uber/jaeger-lib v2.4.0+incompatible // indirect
go.mongodb.org/mongo-driver v1.7.2
go.uber.org/atomic v1.7.0 // indirect
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164 // indirect
)
61 changes: 61 additions & 0 deletions go.sum

Large diffs are not rendered by default.

17 changes: 14 additions & 3 deletions internal/api/handler/todo_handler.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package handler

import (
"github.com/pkg/errors"
"net/http"

"github.com/opentracing/opentracing-go"
log "github.com/sirupsen/logrus"

"github.com/gin-gonic/gin"
"github.com/mecitsemerci/go-todo-app/internal/api/dto"
Expand Down Expand Up @@ -53,6 +55,7 @@ func (h *TodoHandler) GetAll(ctx *gin.Context) {

todoList, err := h.TodoService.GetAll(spanContext)
if err != nil {
log.Error(errors.Wrap(err, "get all failed"))
httperror.NewError(ctx, http.StatusUnprocessableEntity, "Something went wrong!", err)
return
}
Expand Down Expand Up @@ -81,19 +84,18 @@ func (h *TodoHandler) Find(ctx *gin.Context) {
defer span.Finish()

todoID := ctx.Param("id")

if check.IsEmptyOrWhiteSpace(todoID) {
log.Error("todo ID is empty error")
httperror.NewError(ctx, http.StatusBadRequest, "ID is empty.", nil)
return
}

todoModel, err := h.TodoService.Find(spanContext, domain.ID(todoID))

if err != nil {
log.Error(errors.Wrap(err, "item not exist"))
httperror.NewError(ctx, http.StatusUnprocessableEntity, "Item is not exist.", err)
return
}

todoOutput := dto.TodoOutput{}

ctx.JSON(http.StatusOK, todoOutput.FromModel(todoModel))
Expand All @@ -118,18 +120,21 @@ func (h *TodoHandler) Create(ctx *gin.Context) {
var createTodoInput dto.CreateTodoInput

if err := ctx.ShouldBindJSON(&createTodoInput); err != nil {
log.Error(errors.Wrap(err, "invalid request error"))
httperror.NewError(ctx, http.StatusBadRequest, "Request model is invalid.", err)
return
}

if err := validator.Validate(createTodoInput); err != nil {
log.Error(errors.Wrap(err, "validation error"))
httperror.NewError(ctx, http.StatusBadRequest, "Validation error", err)
return
}

todoID, err := h.TodoService.Create(spanContext, createTodoInput.ToModel())

if err != nil {
log.Error(errors.Wrap(err, "item create error"))
httperror.NewError(ctx, http.StatusUnprocessableEntity, "The item failed to create.", err)
return
}
Expand Down Expand Up @@ -160,18 +165,21 @@ func (h *TodoHandler) Update(ctx *gin.Context) {
todoID := ctx.Param("id")

if check.IsEmptyOrWhiteSpace(todoID) {
log.Error("todo ID is empty error")
httperror.NewError(ctx, http.StatusBadRequest, "ID is invalid.", nil)
return
}

var updateTodoInput dto.UpdateTodoInput

if err := ctx.ShouldBindJSON(&updateTodoInput); err != nil {
log.Error(errors.Wrap(err, "invalid request error"))
httperror.NewError(ctx, http.StatusBadRequest, "Request model is invalid.", err)
return
}

if err := validator.Validate(updateTodoInput); err != nil {
log.Error(errors.Wrap(err, "validation error"))
httperror.NewError(ctx, http.StatusBadRequest, "Validation error", err)
return
}
Expand All @@ -181,6 +189,7 @@ func (h *TodoHandler) Update(ctx *gin.Context) {
err := h.TodoService.Update(spanContext, model)

if err != nil {
log.Error(errors.Wrap(err, "item update error"))
httperror.NewError(ctx, http.StatusNotFound, "The item failed to update.", err)
return
}
Expand All @@ -207,13 +216,15 @@ func (h *TodoHandler) Delete(ctx *gin.Context) {
todoID := ctx.Param("id")

if check.IsEmptyOrWhiteSpace(todoID) {
log.Error("todo ID is empty error")
httperror.NewError(ctx, http.StatusBadRequest, "ID is empty.", nil)
return
}

err := h.TodoService.Delete(spanContext, domain.ID(todoID))

if err != nil {
log.Error(errors.Wrap(err, "item delete error"))
httperror.NewError(ctx, http.StatusNotFound, "The item failed to delete.", err)
return
}
Expand Down
12 changes: 12 additions & 0 deletions internal/config/configuration.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package config

import (
"io/ioutil"

"github.com/caarlos0/env/v6"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
)

var (
Expand All @@ -12,6 +16,14 @@ var (
RedisConfig RedisConfiguration
)

func init() {
log.SetFormatter(&log.JSONFormatter{})
// log only debug mode
if gin.Mode() != gin.DebugMode {
log.SetOutput(ioutil.Discard)
}
}

//Load initialize environment variables
func Load() {
_ = env.Parse(&RedisConfig)
Expand Down
3 changes: 2 additions & 1 deletion internal/core/services/todo_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"

"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"

"github.com/mecitsemerci/go-todo-app/internal/core/domain"
"github.com/mecitsemerci/go-todo-app/internal/core/domain/todo"
Expand Down Expand Up @@ -57,7 +58,7 @@ func (srv *TodoService) Create(ctx context.Context, todo todo.Todo) (domain.ID,
id, err := srv.todoRepository.Insert(spanContext, todo)

if err != nil {
return domain.ZeroID, err
return domain.ZeroID, errors.Wrap(err, "insert failed")
}
return id, nil
}
Expand Down
9 changes: 5 additions & 4 deletions internal/core/services/todo_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ package services

import (
"context"
"errors"
"testing"
"time"

"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"

"github.com/mecitsemerci/go-todo-app/internal/core/domain"
"github.com/mecitsemerci/go-todo-app/internal/core/domain/todo"
"github.com/mecitsemerci/go-todo-app/internal/core/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)

type TodoServiceTestSuite struct {
Expand Down Expand Up @@ -194,7 +195,7 @@ func (s *TodoServiceTestSuite) Test_Create_Todo_Should_Return_Error_When_Connect

// Then
assert.NotNil(s.T(), err)
assert.Equal(s.T(), errorMessage.Error(), err.Error())
assert.Equal(s.T(), errors.Wrap(errorMessage, "insert failed").Error(), err.Error())
assert.Equal(s.T(), domain.ZeroID, id)
}

Expand Down

0 comments on commit 77cda0a

Please sign in to comment.