-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Halif Yama
committed
Jan 11, 2024
1 parent
c3166f6
commit 8d4d218
Showing
226 changed files
with
6,099 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Binaries for programs and plugins | ||
*.exe | ||
*.exe~ | ||
*.dll | ||
*.so | ||
*.dylib | ||
|
||
# Test binary, built with `go test -c` | ||
*.test | ||
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out | ||
|
||
# Dependency directories (remove the comment below to include it) | ||
# vendor/ | ||
.DS_Store | ||
TODO.md | ||
logs.txt | ||
.idea/ | ||
secret.md | ||
# app.env | ||
tmp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
dev: | ||
docker-compose up -d | ||
|
||
dev-down: | ||
docker-compose down | ||
|
||
start-server: | ||
air | ||
|
||
install-modules: | ||
go get github.com/gofiber/fiber/v2 | ||
go get github.com/google/uuid | ||
go get github.com/go-playground/validator/v10 | ||
go get -u gorm.io/gorm | ||
go get gorm.io/driver/postgres | ||
go get github.com/spf13/viper | ||
go install github.com/cosmtrek/air@latest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,28 @@ | ||
# crud_pokemon_test | ||
go/gorm/fiber/mariadb | ||
# Create CRUD API in Golang using Fiber and GORM | ||
|
||
In this article, you'll learn how to build a CRUD API in Golang using the Fiber web framework and GORM. The REST API will run on a Fiber HTTP server and use GORM to persist data in a PostgreSQL database. | ||
|
||
 | ||
|
||
## Topics Covered | ||
|
||
- Run the Golang Fiber Project Locally | ||
- Run the Fiber API with React.js App | ||
- Setup the Golang Project | ||
- Setup Postgres and pgAdmin with Docker | ||
- Design the Database Model with GORM | ||
- Load Environment Variables and Connect to Postgres | ||
- Load the Environment Variables | ||
- Connect to the Postgres Server | ||
- Database Migration with GORM | ||
- Implement the CRUD Functionalities | ||
- Add New Record | ||
- Fetch All Records | ||
- Edit a Record | ||
- Retrieve a Single Record | ||
- Delete a Record | ||
- Create the API Routes and Add CORS | ||
|
||
|
||
Read the entire article here: [https://codevoweb.com/create-crud-api-in-golang-using-fiber-and-gorm/](https://codevoweb.com/create-crud-api-in-golang-using-fiber-and-gorm/) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
POSTGRES_HOST=127.0.0.1 | ||
POSTGRES_PORT=6500 | ||
POSTGRES_USER=admin | ||
POSTGRES_PASSWORD=password123 | ||
POSTGRES_DB=golang_fiber | ||
|
||
DATABASE_URL=postgresql://admin:password123@localhost:6500/golang_fiber?schema=public | ||
|
||
CLIENT_ORIGIN=http://localhost:3000 | ||
|
||
PGADMIN_DEFAULT_EMAIL=[email protected] | ||
PGADMIN_DEFAULT_PASSWORD=password123 | ||
|
||
|
||
MARIADB_HOST=localhost | ||
MARIADB_PORT=3306 | ||
MARIADB_USER=dbuser | ||
MARIADB_PASSWORD=v4wedsavhoqwd | ||
MARIADB_DB=golangstarter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package controllers | ||
|
||
import ( | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"go-fiber-service/initializers" | ||
"go-fiber-service/models" | ||
|
||
"github.com/gofiber/fiber/v2" | ||
"gorm.io/gorm" | ||
) | ||
|
||
func CreateNoteHandler(c *fiber.Ctx) error { | ||
var payload *models.CreateNoteSchema | ||
|
||
if err := c.BodyParser(&payload); err != nil { | ||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"status": "fail", "message": err.Error()}) | ||
} | ||
|
||
errors := models.ValidateStruct(payload) | ||
if errors != nil { | ||
return c.Status(fiber.StatusBadRequest).JSON(errors) | ||
|
||
} | ||
|
||
now := time.Now() | ||
newNote := models.Note{ | ||
Title: payload.Title, | ||
Content: payload.Content, | ||
Category: payload.Category, | ||
Published: payload.Published, | ||
CreatedAt: now, | ||
UpdatedAt: now, | ||
} | ||
|
||
result := initializers.DB.Create(&newNote) | ||
|
||
if result.Error != nil && strings.Contains(result.Error.Error(), "duplicate key value violates unique") { | ||
return c.Status(fiber.StatusConflict).JSON(fiber.Map{"status": "fail", "message": "Title already exist, please use another title"}) | ||
} else if result.Error != nil { | ||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"status": "error", "message": result.Error.Error()}) | ||
} | ||
|
||
return c.Status(fiber.StatusCreated).JSON(fiber.Map{"status": "success", "data": fiber.Map{"note": newNote}}) | ||
} | ||
|
||
func FindNotes(c *fiber.Ctx) error { | ||
var page = c.Query("page", "1") | ||
var limit = c.Query("limit", "10") | ||
|
||
intPage, _ := strconv.Atoi(page) | ||
intLimit, _ := strconv.Atoi(limit) | ||
offset := (intPage - 1) * intLimit | ||
|
||
var notes []models.Note | ||
results := initializers.DB.Limit(intLimit).Offset(offset).Find(¬es) | ||
if results.Error != nil { | ||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"status": "error", "message": results.Error}) | ||
} | ||
|
||
return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "success", "results": len(notes), "notes": notes}) | ||
} | ||
|
||
func UpdateNote(c *fiber.Ctx) error { | ||
noteId := c.Params("noteId") | ||
|
||
var payload *models.UpdateNoteSchema | ||
|
||
if err := c.BodyParser(&payload); err != nil { | ||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"status": "fail", "message": err.Error()}) | ||
} | ||
|
||
var note models.Note | ||
result := initializers.DB.First(¬e, "id = ?", noteId) | ||
if err := result.Error; err != nil { | ||
if err == gorm.ErrRecordNotFound { | ||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"status": "fail", "message": "No note with that Id exists"}) | ||
} | ||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"status": "fail", "message": err.Error()}) | ||
} | ||
|
||
updates := make(map[string]interface{}) | ||
if payload.Title != "" { | ||
updates["title"] = payload.Title | ||
} | ||
if payload.Category != "" { | ||
updates["category"] = payload.Category | ||
} | ||
if payload.Content != "" { | ||
updates["content"] = payload.Content | ||
} | ||
|
||
if payload.Published != nil { | ||
updates["published"] = payload.Published | ||
} | ||
|
||
updates["updated_at"] = time.Now() | ||
|
||
initializers.DB.Model(¬e).Updates(updates) | ||
|
||
return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "success", "data": fiber.Map{"note": note}}) | ||
} | ||
|
||
func FindNoteById(c *fiber.Ctx) error { | ||
noteId := c.Params("noteId") | ||
|
||
var note models.Note | ||
result := initializers.DB.First(¬e, "id = ?", noteId) | ||
if err := result.Error; err != nil { | ||
if err == gorm.ErrRecordNotFound { | ||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"status": "fail", "message": "No note with that Id exists"}) | ||
} | ||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"status": "fail", "message": err.Error()}) | ||
} | ||
|
||
return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "success", "data": fiber.Map{"note": note}}) | ||
} | ||
|
||
func DeleteNote(c *fiber.Ctx) error { | ||
noteId := c.Params("noteId") | ||
|
||
result := initializers.DB.Delete(&models.Note{}, "id = ?", noteId) | ||
|
||
if result.RowsAffected == 0 { | ||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"status": "fail", "message": "No note with that Id exists"}) | ||
} else if result.Error != nil { | ||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"status": "error", "message": result.Error}) | ||
} | ||
|
||
return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "success", "message": "Delete success"}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package controllers | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"go-fiber-service/initializers" | ||
"go-fiber-service/models" | ||
|
||
"github.com/gofiber/fiber/v2" | ||
"gorm.io/gorm" | ||
) | ||
|
||
func CreatePokemonHandler(c *fiber.Ctx) error { | ||
var payload *models.CreatePokemonSchema | ||
|
||
if err := c.BodyParser(&payload); err != nil { | ||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"status": "fail", "message": err.Error()}) | ||
} | ||
|
||
errors := models.ValidateStruct(payload) | ||
if errors != nil { | ||
return c.Status(fiber.StatusBadRequest).JSON(errors) | ||
|
||
} | ||
|
||
now := time.Now() | ||
newPokemon := models.Pokemon{ | ||
Num: payload.Num, | ||
Name: payload.Name, | ||
Img: payload.Img, | ||
Type: payload.Type, | ||
Height: payload.Height, | ||
Weight: payload.Weight, | ||
Candy: payload.Candy, | ||
Egg: payload.Egg, | ||
Multipliers: payload.Multipliers, | ||
Weaknesses: payload.Weaknesses, | ||
CandyCount: payload.CandyCount, | ||
SpawnChance: payload.SpawnChance, | ||
AvgSpawns: payload.AvgSpawns, | ||
SpawnTime: payload.SpawnTime, | ||
PrevEvolution: payload.PrevEvolution, | ||
NextEvolution: payload.NextEvolution, | ||
CreatedAt: now, | ||
UpdatedAt: now, | ||
} | ||
|
||
result := initializers.DB.Create(&newPokemon) | ||
|
||
if result.Error != nil && strings.Contains(result.Error.Error(), "duplicate key value violates unique") { | ||
return c.Status(fiber.StatusConflict).JSON(fiber.Map{"status": "fail", "message": "Title already exist, please use another title"}) | ||
} else if result.Error != nil { | ||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"status": "error", "message": result.Error.Error()}) | ||
} | ||
|
||
return c.Status(fiber.StatusCreated).JSON(fiber.Map{"status": "success", "data": fiber.Map{"pokemon": newPokemon}}) | ||
} | ||
|
||
func FindPokemons(c *fiber.Ctx) error { | ||
var page = c.Query("page", "1") | ||
var limit = c.Query("limit", "10") | ||
|
||
intPage, _ := strconv.Atoi(page) | ||
intLimit, _ := strconv.Atoi(limit) | ||
offset := (intPage - 1) * intLimit | ||
|
||
var pokemons []models.Pokemon | ||
results := initializers.DB.Limit(intLimit).Offset(offset).Find(&pokemons) | ||
if results.Error != nil { | ||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"status": "error", "message": results.Error}) | ||
} | ||
|
||
return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "success", "results": len(pokemons), "data": pokemons}) | ||
} | ||
|
||
func UpdatePokemon(c *fiber.Ctx) error { | ||
pokemonId := c.Params("pokemonId") | ||
var payload *models.UpdatePokemonSchema | ||
if err := c.BodyParser(&payload); err != nil { | ||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"status": "fail", "message": err.Error()}) | ||
} | ||
var pokemon models.Pokemon | ||
result := initializers.DB.First(&pokemon, "id = ?", pokemonId) | ||
if err := result.Error; err != nil { | ||
if err == gorm.ErrRecordNotFound { | ||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"status": "fail", "message": "No pokemon with that Id exists"}) | ||
} | ||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"status": "fail", "message": err.Error()}) | ||
} | ||
fmt.Println("UPDATEING") | ||
updates := mapToUpdatePokemon(payload) | ||
|
||
initializers.DB.Model(&pokemon).Updates(updates) | ||
|
||
return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "success", "data": fiber.Map{"pokemon": pokemon}}) | ||
} | ||
|
||
func FindPokemonById(c *fiber.Ctx) error { | ||
pokemonId := c.Params("pokemonId") | ||
|
||
var pokemon models.Pokemon | ||
result := initializers.DB.First(&pokemon, "id = ?", pokemonId) | ||
if err := result.Error; err != nil { | ||
if err == gorm.ErrRecordNotFound { | ||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"status": "fail", "message": "No note with that Id exists"}) | ||
} | ||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"status": "fail", "message": err.Error()}) | ||
} | ||
|
||
return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "success", "data": fiber.Map{"pokemon": pokemon}}) | ||
} | ||
|
||
func DeletePokemon(c *fiber.Ctx) error { | ||
pokemonId := c.Params("pokemonId") | ||
|
||
result := initializers.DB.Delete(&models.Pokemon{}, "id = ?", pokemonId) | ||
|
||
if result.RowsAffected == 0 { | ||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"status": "fail", "message": "No note with that Id exists"}) | ||
} else if result.Error != nil { | ||
return c.Status(fiber.StatusBadGateway).JSON(fiber.Map{"status": "error", "message": result.Error}) | ||
} | ||
|
||
return c.Status(fiber.StatusOK).JSON(fiber.Map{"status": "success", "message": "Delete success"}) | ||
} | ||
|
||
func mapToUpdatePokemon(payload *models.UpdatePokemonSchema) models.UpdatePokemonSchema { | ||
update := models.UpdatePokemonSchema{ | ||
Num: payload.Num, | ||
Name: payload.Name, | ||
Img: payload.Name, | ||
Type: payload.Type, | ||
Height: payload.Height, | ||
Weight: payload.Weight, | ||
Candy: payload.Candy, | ||
Egg: payload.Egg, | ||
Multipliers: payload.Multipliers, | ||
Weaknesses: payload.Weaknesses, | ||
CandyCount: payload.CandyCount, | ||
SpawnChance: payload.SpawnChance, | ||
AvgSpawns: payload.AvgSpawns, | ||
SpawnTime: payload.SpawnTime, | ||
PrevEvolution: payload.PrevEvolution, | ||
NextEvolution: payload.NextEvolution, | ||
UpdatedAt: time.Now(), | ||
} | ||
|
||
return update | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[mariadb-client] | ||
port=3306 | ||
socket=/run/mysqld/mysqld.sock | ||
user=healthcheck | ||
password=L3zl&&|nuJaI2tz~$]%nrzPv5AIF?ga^ | ||
protocol=tcp | ||
|
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
default-character-set=utf8mb4 | ||
default-collation=utf8mb4_general_ci |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Oops, something went wrong.