Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Halif Yama committed Jan 11, 2024
1 parent c3166f6 commit 8d4d218
Show file tree
Hide file tree
Showing 226 changed files with 6,099 additions and 2 deletions.
22 changes: 22 additions & 0 deletions .gitignore
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
17 changes: 17 additions & 0 deletions Makefile
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
30 changes: 28 additions & 2 deletions README.md
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.

![Create CRUD API in Golang using Fiber and GORM](https://codevoweb.com/wp-content/uploads/2023/01/Create-CRUD-API-in-Golang-using-Fiber-and-GORM.webp)

## 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/)

19 changes: 19 additions & 0 deletions app.env
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
133 changes: 133 additions & 0 deletions controllers/note.controller.go
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(&notes)
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(&note, "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(&note).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(&note, "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"})
}
152 changes: 152 additions & 0 deletions controllers/pokemon.controller.go
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
}
7 changes: 7 additions & 0 deletions database/.my-healthcheck.cnf
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 added database/aria_log.00000001
Binary file not shown.
Binary file added database/aria_log_control
Binary file not shown.
2 changes: 2 additions & 0 deletions database/golangstarter/db.opt
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 added database/golangstarter/notes.frm
Binary file not shown.
Binary file added database/golangstarter/notes.ibd
Binary file not shown.
Binary file added database/golangstarter/pokemons.frm
Binary file not shown.
Binary file added database/golangstarter/pokemons.ibd
Binary file not shown.
Loading

0 comments on commit 8d4d218

Please sign in to comment.