Go JWT Auth (Fiber & Mongo)
Template create for use as CookieCutter for my Golang projects.
The hardest part for start a project for me was to chose Stack and create the initial login and integrations
like logger, database, etc. So I decided to create a template with everything already working.
All the project is based in interfaces that mean you can implement your own logic and use it in the project.
example: you can use different database like Postgres, MySQL, etc. Just implement the interface and use it.
Stack
Before the execution
- Modify the file
./config/env.json
with your parameters - Install gomock
go install go.uber.org/mock/mockgen@latest
- Install swag
go install github.com/swaggo/swag/cmd/swag@latest
Routes
You can also check in the route /swagger/index.html after run the project 🤩.
Note 📝: For add a private route you need to create it in the private router v1Private
inside the pkg/server/server.go file.
Name | Path | Method | Description | Request | Response |
---|
Register | /api/v1/register | POST | Create a new user | email,password | |
Login | /api/v1/login | POST | Login a user | email,password | token |
Metrics | /metrics | GET | Monitor for your API | | html |
Documentation | /docs | GET | Documentation | | html |
How to use
For this example we will make suppose that you want to create endpoints for Blog Posts.
-
Create a new folder inside the internal folder with the name of your entity. In this case post
.
-
Create tree folders inside the entity folder: application
, domain
and infrastructure
.
-
Create two folders inside the domain folder: ports
and model
.
-
Create a file inside the model folder with the name of your entity. In this case post.go
and define your struct Post
.
package model
import "time"
type Post struct {
ID string `json:"id" bson:"_id"`
Title string `json:"title" bson:"title"`
Content string `json:"content" bson:"content"`
CreatedAt time.Time `json:"created_at" bson:"created_at"`
UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
}
-
Create 3 files inside the ports folder: repository.go
, handlers.go
and application.go
.
-
Define your interfaces inside the repository.go
,handlers.go
and application.go
file.
package ports
import "github.com/your_user/your_project/internal/post/domain/model"
type PostRepository interface {
Create(post *model.Post) error
FindAll() ([]*model.Post, error)
FindByID(id string) (*model.Post, error)
Update(post *model.Post) error
Delete(id string) error
}
-
Modify the scripts/generate-mocks.sh
file and add your three new interfaces.
mockgen -destination=pkg/mocks/mock_post_application.go -package=mocks --build_flags=--mod=mod github.com/solrac97gr/go-jwt-auth/internal/post/domain/ports PostApplication &&
mockgen -destination=pkg/mocks/mock_post_repository.go -package=mocks --build_flags=--mod=mod github.com/solrac97gr/go-jwt-auth/internal/post/domain/ports PostRepository &&
mockgen -destination=pkg/mocks/mock_post_handlers.go -package=mocks --build_flags=--mod=mod github.com/solrac97gr/go-jwt-auth/internal/post/domain/ports PostHandlers
-
Run the scripts/generate-mocks.sh
file.
-
Now is time for implement your interfaces. Create two folders inside the infrastructure
folder with the name of repositories
and handlers
.
-
Create a file inside the repositories
folder with the name of your interface implementation. In this case mongo.go
and implement the PostRepository
interface.
package repositories
type MongoPostRepository struct {
db *mongo.Database
logger logger.LoggerApplication
configurator config.ConfigApplication
}
func NewMongoPostRepository(db *mongo.Database) *MongoPostRepository {
return &MongoPostRepository{db: db}
}
func (m *MongoPostRepository) Create(post *model.Post) error {
_, err := m.db.Collection("posts").InsertOne(context.Background(), post)
if err != nil {
m.logger.Error("Error creating post", err)
return err
}
return nil
}
.
.
.
- Create a file inside the
handlers
folder with the name of your interface implementation. In this case http.go
and implement the PostHandler
interface.
package handlers
type HTTPPostHandler struct {
postApplication ports.PostApplication
logger logger.LoggerApplication
validator validator.ValidatorApplication
}
func NewHTTPPostHandler(postApplication ports.PostApplication) *HTTPPostHandler {
return &HTTPPostHandler{postApplication: postApplication}
}
func (h *HTTPPostHandler) CreatePost(c *fiber.Ctx) error {
post := &model.Post{}
if err := c.BodyParser(post); err != nil {
h.logger.Error("Error parsing post", err)
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
}
if err := h.postApplication.Create(post); err != nil {
h.logger.Error("Error creating post", err)
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
return c.Status(http.StatusCreated).JSON(fiber.Map{"message": "Post created successfully"})
}
.
.
.
- Add your handlers to new routes depends on if it's public or private. In this case we will add it to the private routes in file
pkg/server/server.go
.
v1Private.Post("/posts", h.postHandler.CreatePost)
- If you want to add it to the swagger documentation view use comment with special annotation for your handlers.
func (h *HTTPPostHandler) CreatePost(c *fiber.Ctx) error {
.
.
.
}
- Generate the swagger documentation with the command
/scripts/generate-docs.sh
. - Run the project with the command
go run cmd/http/main.go
or with the script scripts/run.sh
.
Considerations
- The
scripts/generate-mocks.sh
file is used to generate the mocks of the interfaces. - The
scripts/generate-docs.sh
file is used to generate the swagger documentation. - The
scripts/run.sh
file is used to run the project. - The
scripts/run-tests.sh
file is used to run the tests. - The
scripts/run-tests-coverage.sh
file is used to run the tests with coverage. - For avoid create users with same mail, make the mail field unique in the database (mongo index in this case).
License
Apache License 2.0