├── Dockerfile
├── README.md
├── cmd
└── main.go
├── controller
└── product_controller.go
├── db
└── conn.go
├── go.mod
├── go.sum
├── middleware
└── auth.go
├── model
├── product.go
└── response.go
├── repository
└── product_repository.go
└── usecase
└── product_usecase.go
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.18
2 |
3 | WORKDIR /go/src/app
4 |
5 | COPY . .
6 |
7 | EXPOSE 8000
8 |
9 | RUN go build -o main cmd/main.go
10 |
11 | CMD ["./main"]
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # API-GO: Product Management with JWT Verification
2 |
3 | This project is an API for product management developed in **Go** using the **Gin** framework. The architecture is modular, ensuring better organization and maintainability.
4 |
5 |
6 |
7 | ---
8 |
9 | ## 🚀 Project Initialization
10 |
11 |
12 | ### Pre-requisites
13 |
14 | Make sure you have installed:
15 | - **Golang**: [Install Golang](https://go.dev/doc/install)
16 | - **Docker**: [Install Docker](https://www.docker.com/products/docker-desktop)
17 |
18 | ---
19 |
20 | ### How to Run
21 |
22 | 1. Clone the project and navigate to the folder:
23 | ```bash
24 | git clone https://github.com/usuario/api-go.git
25 | cd api-go
26 | ```
27 |
28 | 2. Configure the database connection:
29 | Edit the settings in the `db/conn.go` file to reflect your credentials.
30 |
31 | 3. Start the services with Docker:
32 | ```bash
33 | docker-compose up
34 | ```
35 |
36 | 4. Access the API at the address:
37 | - `http://localhost:8000`
38 |
39 | ---
40 |
41 | ## 📚 Project Structure
42 |
43 | The structure is organized as follows:
44 |
45 | ```plaintext
46 | API-GO/
47 | ├── cmd/
48 | │ └── main.go # Main file to start the application
49 | ├── controller/
50 | │ └── product_controller.go # Controllers responsible for the routes
51 | ├── db/
52 | │ └── conn.go # Database configuration and connection
53 | ├── model/
54 | │ ├── product.go # Product model
55 | │ └── response.go # Response structures for the API
56 | ├── repository/
57 | │ └── product_repository.go # Layer for interacting with the database
58 | ├── usecase/
59 | │ └── product_usecase.go # Business logic and application logic
60 | ├── .gitignore # Files ignored in version control
61 | ├── docker-compose.yml # Docker Compose configuration
62 | ├── Dockerfile # Docker container configuration
63 | ├── go.mod # Project dependencies
64 | ├── go.sum # Dependency hashes
65 | └── README.md # Project documentation
66 | ```
67 |
68 | ---
69 |
70 | ## 📖 Endpoints
71 |
72 | ### **Ping**
73 | - **GET `/ping`**
74 | - Returns a test message.
75 | - **Response**:
76 | ```json
77 | {
78 | "message": "initial tests"
79 | }
80 | ```
81 |
82 | ---
83 |
84 | ### **Products**
85 | - **GET `/products`**
86 | - Lists all registered products.
87 | - **Example Response**:
88 | ```json
89 | [
90 | {
91 | "id": 1,
92 | "name": "Product 1",
93 | "price": 100.00
94 | },
95 | {
96 | "id": 2,
97 | "name": "Product 2",
98 | "price": 150.00
99 | }
100 | ]
101 | ```
102 |
103 | - **POST `/product`**
104 | - Creates a new product.
105 | - **Body**:
106 | ```json
107 | {
108 | "name": "Sample Product",
109 | "price": 100.00
110 | }
111 | ```
112 | - **Example Response**:
113 | ```json
114 | {
115 | "id": 1,
116 | "name": "Sample Product",
117 | "price": 100.00
118 | }
119 | ```
120 |
121 | - **GET `/product/:productId`**
122 | - Returns a specific product based on the ID.
123 | - **Example Response**:
124 | ```json
125 | {
126 | "id": 1,
127 | "name": "Sample Product",
128 | "price": 100.00
129 | }
130 | ```
131 |
132 | - **PUT `/product`**
133 | - Updates an existing product.
134 | - **Body**:
135 | ```json
136 | {
137 | "id": 1,
138 | "name": "Updated Product",
139 | "price": 150.00
140 | }
141 | ```
142 | - **Example Response**:
143 | ``` json
144 | {
145 | "id": 1,
146 | "name": "Updated Product",
147 | "price": 150.00
148 | }
149 | ```
150 |
151 | - **DELETE `/product/:productId`**
152 | - Removes a product based on the ID.
153 | - **Example Response**:
154 | ``` json
155 | {
156 | "message": "Product successfully removed"
157 | }
158 | ```
159 |
160 | ---
161 |
162 | ## 🛠️ Technologies Used
163 |
164 | - **Golang**: Main programming language.
165 | - **Gin**: Lightweight and fast framework for API development.
166 | - **Docker**: For container creation and management.
167 | - **PostgreSQL** (or another relational database): Configured in the `db` module.
168 |
169 |
170 |
171 | ---
172 |
--------------------------------------------------------------------------------
/cmd/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "api-go/controller"
5 | "api-go/db"
6 | "api-go/middleware"
7 | "api-go/repository"
8 | "api-go/usecase"
9 | "github.com/gin-gonic/gin"
10 | )
11 |
12 | func main() {
13 | server := gin.Default()
14 |
15 | dbConnection, err := db.ConnectDb()
16 |
17 | if err != nil {
18 | panic(err)
19 | return err
20 | }
21 |
22 | ProductRepository := repository.NewProductRepository(dbConnection)
23 |
24 | ProductUseCase := usecase.NewProductUseCase(ProductRepository)
25 |
26 | ProductController := controller.NewProductController(*ProductUseCase)
27 |
28 | server.GET("/ping-dev", func(ctx *gin.Context) {
29 | ctx.JSON(200, gin.H{
30 | "message": "Servidor Está ativo!",
31 | })
32 | })
33 |
34 | /*
35 | routes server
36 | products
37 | */
38 |
39 | protected := server.Group("/")
40 | protected.Use(middleware.AuthMiddleware())
41 | {
42 | protected.GET("/products", ProductController.GetProducts)
43 | protected.POST("/product", ProductController.CreateProduct)
44 | protected.GET("/product/:productId", ProductController.GetProductsById)
45 | protected.PUT("/product", ProductController.UpdateProduct)
46 | protected.DELETE("/product/:productId", ProductController.DeleteProduct)
47 | }
48 |
49 | server.Run(":8000")
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/controller/product_controller.go:
--------------------------------------------------------------------------------
1 | package controller
2 |
3 | import (
4 | "api-go/model"
5 | "api-go/usecase"
6 | "net/http"
7 | "strconv"
8 |
9 | "github.com/gin-gonic/gin"
10 | )
11 |
12 | type productController struct {
13 | productUseCase usecase.ProductUseCase
14 | }
15 |
16 | func NewProductController(usecase usecase.ProductUseCase) *productController {
17 | return &productController{
18 | productUseCase: usecase,
19 | }
20 | }
21 |
22 | func (p *productController) GetProducts(ctx *gin.Context) {
23 | products, err := p.productUseCase.GetProducts()
24 | if err != nil {
25 | ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
26 | return
27 | }
28 |
29 | ctx.JSON(http.StatusOK, products)
30 | }
31 |
32 | func (p *productController) CreateProduct(ctx *gin.Context) {
33 |
34 | var product model.Product
35 | err := ctx.BindJSON(&product)
36 | if err != nil {
37 | ctx.JSON(http.StatusBadRequest, err)
38 | return
39 | }
40 |
41 | insertedProduct, err := p.productUseCase.CreateProduct(product)
42 | if err != nil {
43 | ctx.JSON(http.StatusInternalServerError, err)
44 | return
45 | }
46 |
47 | ctx.JSON(http.StatusCreated, insertedProduct)
48 | }
49 |
50 | func (p *productController) GetProductsById(ctx *gin.Context) {
51 |
52 | id := ctx.Param("productId")
53 | if id == "" {
54 | response := model.Response{
55 | Message: "Product ID cannot be null",
56 | }
57 | ctx.JSON(http.StatusBadRequest, response)
58 | return
59 | }
60 |
61 | productId, err := strconv.Atoi(id)
62 | if err != nil {
63 | response := model.Response{
64 | Message: "Product Id need to be number",
65 | }
66 | ctx.JSON(http.StatusBadRequest, response)
67 | return
68 | }
69 |
70 | product, err := p.productUseCase.GetProductById(productId)
71 | if err != nil {
72 | ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
73 | return
74 | }
75 |
76 | if product == nil {
77 | response := model.Response{
78 | Message: "Product not existing in database",
79 | }
80 | ctx.JSON(http.StatusNotFound, response)
81 | return
82 | }
83 |
84 | ctx.JSON(http.StatusOK, product)
85 | }
86 |
87 | func (p *productController) UpdateProduct(ctx *gin.Context) {
88 | var product model.Product
89 | err := ctx.BindJSON(&product)
90 | if err != nil {
91 | ctx.JSON(http.StatusBadRequest, err)
92 | return
93 | }
94 |
95 | err = p.productUseCase.UpdateProduct(product)
96 | if err != nil {
97 | ctx.JSON(http.StatusInternalServerError, err)
98 | return
99 | }
100 |
101 | ctx.JSON(http.StatusOK, product)
102 | }
103 |
104 | func (p *productController) DeleteProduct(ctx *gin.Context) {
105 | id := ctx.Param("productId")
106 | if id == "" {
107 | response := model.Response{
108 | Message: "Product ID cannot be null",
109 | }
110 | ctx.JSON(http.StatusBadRequest, response)
111 | return
112 | }
113 |
114 | productId, err := strconv.Atoi(id)
115 | if err != nil {
116 | response := model.Response{
117 | Message: "Product Id need to be number",
118 | }
119 | ctx.JSON(http.StatusBadRequest, response)
120 | return
121 | }
122 |
123 | err = p.productUseCase.DeleteProduct(productId)
124 | if err != nil {
125 | ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
126 | return
127 | }
128 |
129 | response := model.Response{
130 | Message: "Product deleted successfully",
131 | }
132 | ctx.JSON(http.StatusOK, response)
133 | }
134 |
--------------------------------------------------------------------------------
/db/conn.go:
--------------------------------------------------------------------------------
1 | package db
2 |
3 | import (
4 | "database/sql"
5 | "fmt"
6 |
7 | _ "github.com/lib/pq"
8 | )
9 |
10 | /*
11 | configuration
12 | db
13 | */
14 |
15 | /*
16 | var (
17 | host = "go_db" string
18 | port = 5432 int
19 | user = "postgres" string
20 | password = "1234" int
21 | dbname = "postgres"
22 |
23 | )*/
24 |
25 | const (
26 | host = "go_db"
27 | port = 5432
28 | user = "postgres"
29 | password = "1234"
30 | dbname = "postgres"
31 | )
32 |
33 | func ConnectDb() (*sql.DB, error) {
34 | psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
35 | "password=%s dbname=%s sslmode=disable",
36 | host, port, user, password, dbname)
37 | db, err := sql.Open("postgres", psqlInfo)
38 | if err != nil {
39 | panic(err)
40 | }
41 |
42 | err = db.Ping()
43 | if err != nil {
44 | panic(err)
45 | }
46 |
47 | //fmt.Println("connected to" + dbname)
48 |
49 | return db, nil
50 | }
51 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module api-go
2 |
3 | go 1.23.4
4 |
5 | require (
6 | github.com/gin-gonic/gin v1.10.0
7 | github.com/lib/pq v1.10.9
8 | )
9 |
10 | require (
11 | github.com/bytedance/sonic v1.11.6 // indirect
12 | github.com/bytedance/sonic/loader v0.1.1 // indirect
13 | github.com/cloudwego/base64x v0.1.4 // indirect
14 | github.com/cloudwego/iasm v0.2.0 // indirect
15 | github.com/dgrijalva/jwt-go v3.2.0+incompatible // direct
16 | github.com/gabriel-vasile/mimetype v1.4.3 // indirect
17 | github.com/gin-contrib/sse v0.1.0 // indirect
18 | github.com/go-playground/locales v0.14.1 // indirect
19 | github.com/go-playground/universal-translator v0.18.1 // indirect
20 | github.com/go-playground/validator/v10 v10.20.0 // indirect
21 | github.com/goccy/go-json v0.10.2 // indirect
22 | github.com/json-iterator/go v1.1.12 // indirect
23 | github.com/klauspost/cpuid/v2 v2.2.7 // indirect
24 | github.com/leodido/go-urn v1.4.0 // indirect
25 | github.com/mattn/go-isatty v0.0.20 // indirect
26 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
27 | github.com/modern-go/reflect2 v1.0.2 // indirect
28 | github.com/pelletier/go-toml/v2 v2.2.2 // indirect
29 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
30 | github.com/ugorji/go/codec v1.2.12 // indirect
31 | golang.org/x/arch v0.8.0 // indirect
32 | golang.org/x/crypto v0.23.0 // indirect
33 | golang.org/x/net v0.25.0 // indirect
34 | golang.org/x/sys v0.20.0 // indirect
35 | golang.org/x/text v0.15.0 // indirect
36 | google.golang.org/protobuf v1.34.1 // indirect
37 | gopkg.in/yaml.v3 v3.0.1 // indirect
38 | )
39 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
2 | github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
3 | github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
4 | github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
5 | github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
6 | github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
7 | github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
8 | github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
10 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
12 | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
13 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
14 | github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
15 | github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
16 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
17 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
18 | github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
19 | github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
20 | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
21 | github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
22 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
23 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
24 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
25 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
26 | github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
27 | github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
28 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
29 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
30 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
31 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
32 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
33 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
34 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
35 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
36 | github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
37 | github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
38 | github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
39 | github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
40 | github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
41 | github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
42 | github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
43 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
44 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
45 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
46 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
47 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
48 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
49 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
50 | github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
51 | github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
52 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
53 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
54 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
55 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
56 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
57 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
58 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
59 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
60 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
61 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
62 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
63 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
64 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
65 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
66 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
67 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
68 | github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
69 | github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
70 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
71 | golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
72 | golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
73 | golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
74 | golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
75 | golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
76 | golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
77 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
78 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
79 | golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
80 | golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
81 | golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
82 | golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
83 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
84 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
85 | google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
86 | google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
87 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
88 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
89 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
90 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
91 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
92 | nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
93 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
94 |
--------------------------------------------------------------------------------
/middleware/auth.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | "strings"
7 |
8 | "github.com/dgrijalva/jwt-go"
9 | "github.com/gin-gonic/gin"
10 | )
11 |
12 | var jwtSecret = []byte("your_secret_key")
13 |
14 | func AuthMiddleware() gin.HandlerFunc {
15 | return func(c *gin.Context) {
16 | authHeader := c.GetHeader("Authorization")
17 | if authHeader == "" {
18 | c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header required"})
19 | c.Abort()
20 | return
21 | }
22 |
23 | tokenString := strings.Split(authHeader, "Bearer ")[1]
24 | token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
25 | if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
26 | return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
27 | }
28 | return jwtSecret, nil
29 | })
30 |
31 | if err != nil || !token.Valid {
32 | c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
33 | c.Abort()
34 | return
35 | }
36 |
37 | c.Next()
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/model/product.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | /*
4 | Product Struct
5 | */
6 |
7 | type Product struct {
8 | ID int `json:"id"`
9 | Name string `json:"name"`
10 | Price float64 `json:"price"`
11 | }
--------------------------------------------------------------------------------
/model/response.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type Response struct {
4 | Message string
5 | }
6 |
--------------------------------------------------------------------------------
/repository/product_repository.go:
--------------------------------------------------------------------------------
1 | package repository
2 |
3 | import (
4 | "api-go/model"
5 | "database/sql"
6 | "fmt"
7 | )
8 |
9 | type ProductRepository struct {
10 | connection *sql.DB
11 | }
12 |
13 | func NewProductRepository(connection *sql.DB) ProductRepository {
14 | return ProductRepository{
15 | connection: connection,
16 | }
17 | }
18 |
19 | func (pr *ProductRepository) GetProducts() ([]model.Product, error) {
20 | query := "SELECT id, product_name, price FROM product"
21 | rows, err := pr.connection.Query(query)
22 | if err != nil {
23 | fmt.Println(err)
24 | return []model.Product{}, err
25 | }
26 |
27 | var productList []model.Product
28 | var productObj model.Product
29 |
30 | for rows.Next() {
31 | err = rows.Scan(
32 | &productObj.ID,
33 | &productObj.Name,
34 | &productObj.Price)
35 |
36 | if err != nil {
37 | fmt.Println(err)
38 | return []model.Product{}, err
39 | }
40 |
41 | productList = append(productList, productObj)
42 | }
43 |
44 | rows.Close()
45 |
46 | return productList, nil
47 | }
48 |
49 | func (pr *ProductRepository) CreateProduct(product model.Product) (int, error) {
50 |
51 | var id int
52 | query, err := pr.connection.Prepare("INSERT INTO product" +
53 | "(product_name, price)" +
54 | "VALUES($1, $2) RETURNING id")
55 | if err != nil {
56 | fmt.Println(err)
57 | return 0, err
58 | }
59 |
60 | err = query.QueryRow(product.Name, product.Price).Scan(&id)
61 | if err != nil {
62 | fmt.Println(err)
63 | return 0, err
64 | }
65 |
66 | query.Close()
67 | return id, nil
68 | }
69 |
70 | func (pr *ProductRepository) GetProductById(id_product int) (*model.Product, error) {
71 |
72 | query, err := pr.connection.Prepare("SELECT * FROM product WHERE od = $1")
73 | if err != nil {
74 | fmt.Println(err)
75 | return nil, err
76 | }
77 |
78 | var produto model.Product
79 |
80 | err = query.QueryRow(id_product).Scan(
81 | &produto.ID,
82 | &produto.Name,
83 | &produto.Price,
84 | )
85 |
86 | if err != nil {
87 | if err == sql.ErrNoRows {
88 | return nil, nil
89 | }
90 |
91 | return nil, err
92 | }
93 |
94 | query.Close()
95 | return &produto, nil
96 | }
97 |
98 | func (pr *ProductRepository) UpdateProduct(product model.Product) error {
99 | query, err := pr.connection.Prepare("UPDATE product SET product_name = $1, price = $2 WHERE id = $3")
100 | if err != nil {
101 | fmt.Println(err)
102 | return err
103 | }
104 | defer query.Close()
105 |
106 | _, err = query.Exec(product.Name, product.Price, product.ID)
107 | if err != nil {
108 | fmt.Println(err)
109 | return err
110 | }
111 |
112 | return nil
113 | }
114 |
115 | func (pr *ProductRepository) DeleteProduct(id int) error {
116 | query, err := pr.connection.Prepare("DELETE FROM product WHERE id = $1")
117 | if err != nil {
118 | fmt.Println(err)
119 | return err
120 | }
121 | defer query.Close()
122 |
123 | _, err = query.Exec(id)
124 | if err != nil {
125 | //fmt.Println(err)
126 | return err
127 | }
128 |
129 | return nil
130 | }
131 |
--------------------------------------------------------------------------------
/usecase/product_usecase.go:
--------------------------------------------------------------------------------
1 | package usecase
2 |
3 | import (
4 | "api-go/model"
5 | "api-go/repository"
6 | )
7 |
8 | type ProductUseCase struct {
9 | repository repository.ProductRepository
10 | }
11 |
12 | func NewProductUseCase(repo repository.ProductRepository) *ProductUseCase {
13 | return &ProductUseCase{
14 | repository: repo,
15 | }
16 | }
17 |
18 | func (pu *ProductUseCase) GetProducts() ([]model.Product, error) {
19 | return pu.repository.GetProducts()
20 | }
21 |
22 | func (pu *ProductUseCase) CreateProduct(product model.Product) (model.Product, error) {
23 | productId, err := pu.repository.CreateProduct(product)
24 | if err != nil {
25 | return model.Product{}, err
26 | }
27 | product.ID = productId
28 | return product, nil
29 | }
30 |
31 | func (pu *ProductUseCase) GetProductById(id_product int) (*model.Product, error) {
32 | product, err := pu.repository.GetProductById(id_product)
33 | if err != nil {
34 | return nil, err
35 | }
36 | return product, nil
37 | }
38 |
39 | func (pu *ProductUseCase) UpdateProduct(product model.Product) error {
40 | return pu.repository.UpdateProduct(product)
41 | }
42 |
43 | func (pu *ProductUseCase) DeleteProduct(id int) error {
44 | return pu.repository.DeleteProduct(id)
45 | }
46 |
--------------------------------------------------------------------------------