Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
DB_USER=beeer
DB_PASSWORD=beeer123
DB_HOST=fullstack-postgres
DB_POST=5432
DB_NAME=backend_beers
1 change: 1 addition & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
146 changes: 146 additions & 0 deletions backend/Beers API.postman_collection.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
{
"info": {
"_postman_id": "a78ce2b3-3a22-46f0-b815-b45536581268",
"name": "Beers API",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "12536647"
},
"item": [
{
"name": "Get All Beers",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:5000/api/v1/beer/",
"protocol": "http",
"host": [
"localhost"
],
"port": "5000",
"path": [
"api",
"v1",
"beer",
""
]
}
},
"response": []
},
{
"name": "Get All Bears with paginate",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:5000/api/v1/beers?page=1&page_size=10",
"protocol": "http",
"host": [
"localhost"
],
"port": "5000",
"path": [
"api",
"v1",
"beers"
],
"query": [
{
"key": "page",
"value": "1"
},
{
"key": "page_size",
"value": "10"
}
]
}
},
"response": []
},
{
"name": "Insert a new beer",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"abv\": 8.4,\r\n \"address\": \"141 South Main Street\",\r\n \"category\": \"British Alexandre\",\r\n \"city\": \"Slippery Rock 2\",\r\n \"coordinates\": [\r\n 41.0638,\r\n -80.0556\r\n ],\r\n \"country\": \"United States\",\r\n \"description\": \"This robust, hearty stout is as sturdy as its namesake. Roasted barley is the trademark of stout, a bittersweet separation from its cousin Porter. The deep character of roasted barley is further enhanced by the addition of oatmeal for an incredible silky finish.\",\r\n \"ibu\": 104,\r\n \"name\": \"Stone House Stout\",\r\n \"state\": \"Pennsylvania\",\r\n \"website\": \"http://www.northcountrybrewing.com\"\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:5000/api/v1/beer",
"protocol": "http",
"host": [
"localhost"
],
"port": "5000",
"path": [
"api",
"v1",
"beer"
]
}
},
"response": []
},
{
"name": "Update a beer",
"request": {
"method": "PUT",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"abv\": 8.4,\r\n \"address\": \"141 South Main Street\",\r\n \"category\": \"British Alexandre\",\r\n \"city\": \"Slippery Rock 2\",\r\n \"coordinates\": [\r\n 41.0638,\r\n -80.0556\r\n ],\r\n \"country\": \"United States\",\r\n \"description\": \"This robust, hearty stout is as sturdy as its namesake. Roasted barley is the trademark of stout, a bittersweet separation from its cousin Porter. The deep character of roasted barley is further enhanced by the addition of oatmeal for an incredible silky finish.\",\r\n \"ibu\": 104,\r\n \"name\": \"Stone House Stout\",\r\n \"state\": \"Pennsylvania\",\r\n \"website\": \"http://www.northcountrybrewing.com\"\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:5000/api/v1/beer/19",
"protocol": "http",
"host": [
"localhost"
],
"port": "5000",
"path": [
"api",
"v1",
"beer",
"19"
]
}
},
"response": []
},
{
"name": "Delete a beer",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "http://localhost:5000/api/v1/beer/20",
"protocol": "http",
"host": [
"localhost"
],
"port": "5000",
"path": [
"api",
"v1",
"beer",
"20"
]
}
},
"response": []
}
]
}
20 changes: 20 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM golang:1.19-alpine

WORKDIR /app


COPY go.mod ./
COPY go.sum ./


RUN go mod download

COPY . .

RUN go build -o app

EXPOSE 5000

RUN chmod +x ./app

CMD [ "./app" ]
106 changes: 106 additions & 0 deletions backend/controllers/beer_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package controllers

import (
"net/http"
"strconv"

"github.com/gin-gonic/gin"
"github.com/ronanzindev/backend-test-two/database"
"github.com/ronanzindev/backend-test-two/models"
"github.com/ronanzindev/backend-test-two/utils/errors"
"github.com/ronanzindev/backend-test-two/utils/paginate"
)

func GetAllProducts(c *gin.Context) {
db := database.GetDataBase()
var beers []models.Beer
if err := db.Find(&beers).Error; err != nil {
productsErr := errors.NewBadRequestError("Cannot get all products")
c.JSON(productsErr.Status, productsErr)
}
c.JSON(http.StatusOK, beers)

}

func GetAllProductsPaginate(c *gin.Context) {
db := database.GetDataBase()
var beers []models.Beer
db.Scopes(paginate.Paginate(c)).Find(&beers)
c.JSON(200, beers)
}
func GetProductById(c *gin.Context) {
idParam := c.Param("id")
id, err := strconv.Atoi(idParam)
if err != nil {
idErr := errors.NewBadRequestError("Id must be a integer")
c.JSON(idErr.Status, idErr)
}
db := database.GetDataBase()
var beer models.Beer
err = db.First(&beer, id).Error
if err != nil {
productErr := errors.NewBadRequestError("Product not found")
c.JSON(http.StatusNotFound, productErr)
return
}
c.JSON(http.StatusOK, beer)

}

func CreateProduct(c *gin.Context) {
db := database.GetDataBase()

var beer models.Beer
if err := c.ShouldBindJSON(&beer); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"Error": err.Error()})
return
}

if err := db.Create(&beer).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"Error": err.Error()})
return
}

c.JSON(200, beer)
}

func UpdateProduct(c *gin.Context) {
idParam := c.Param("id")
id, err := strconv.Atoi(idParam)
if err != nil {
idErr := errors.NewBadRequestError("Id must be a integer")
c.JSON(idErr.Status, idErr)
}
db := database.GetDataBase()
var beer models.Beer
err = db.First(&beer, id).Error
if err != nil {
productErr := errors.NewBadRequestError("Product not found")
c.JSON(http.StatusNotFound, productErr)
return
}

if err := c.ShouldBindJSON(&beer); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"Error": err.Error()})
return
}
if err := db.Save(&beer).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"Error": err.Error()})
return
}
c.JSON(http.StatusOK, &beer)
}

func DeleteProduct(c *gin.Context) {
idParam := c.Param("id")
id, err := strconv.Atoi(idParam)
if err != nil {
idErr := errors.NewBadRequestError("Id must be a integer")
c.JSON(idErr.Status, idErr)
}
db := database.GetDataBase()
if err := db.Delete(&models.Beer{}, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"Error": "Product not found"})
}
c.JSON(200, nil)
}
47 changes: 47 additions & 0 deletions backend/database/database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package database

import (
"fmt"
"log"
"os"
"time"

"github.com/joho/godotenv"
"github.com/ronanzindev/backend-test-two/database/migrations"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)

var db *gorm.DB

func readEnvs(key string) string {
godotenv.Load(".env")
return os.Getenv(key)
}

var (
DB_USER string = readEnvs("DB_USER")
DB_PASSWORD string = readEnvs("DB_PASSWORD")
DB_HOST string = readEnvs("DB_HOST")
DB_NAME string = readEnvs("DB_NAME")
DB_POST string = readEnvs("DB_POST")
)

func StartDB() {
url := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=America/Sao_Paulo",
DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, DB_POST)
database, err := gorm.Open(postgres.Open(url), &gorm.Config{SkipDefaultTransaction: true})
if err != nil {
log.Fatal("error :", err)
}
db = database
config, _ := db.DB()
config.SetMaxIdleConns(10)
config.SetMaxOpenConns(10)
config.SetConnMaxLifetime(time.Hour)
migrations.RunMigrations(db)
}

func GetDataBase() *gorm.DB {
return db
}
10 changes: 10 additions & 0 deletions backend/database/migrations/migration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package migrations

import (
"github.com/ronanzindev/backend-test-two/models"
"gorm.io/gorm"
)

func RunMigrations(db *gorm.DB) {
db.AutoMigrate(models.Beer{})
}
30 changes: 30 additions & 0 deletions backend/database/populate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package database

import (
"bytes"
"encoding/json"
"fmt"
"log"
"os"

"github.com/ronanzindev/backend-test-two/models"
)

func PopulateDB() {
db := GetDataBase()
var beers []models.Beer
err := db.Find(&beers).Error
if err != nil {
fmt.Println(err)
}
if len(beers) == 0 {
byteValue, _ := os.ReadFile("db.json")
dec := json.NewDecoder(bytes.NewReader(byteValue))
dec.Decode(&beers)
err = db.CreateInBatches(&beers, 1000).Error
if err != nil {
log.Fatal(err)
}

}
}
File renamed without changes.
Loading