Skip to content
Merged
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 internal/handlers/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package handlers

type Error struct {
Error string `json:"error"`
Comment on lines +3 to +4
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new response type name/field combo results in awkward usage like handlers.Error{Error: ...} and can be confused with Go’s built-in error concept. Consider renaming the struct to something like ErrorResponse (keeping the JSON tag error) and using a field name like Message to make call sites clearer.

Suggested change
type Error struct {
Error string `json:"error"`
type ErrorResponse struct {
Message string `json:"error"`

Copilot uses AI. Check for mistakes.
}
15 changes: 8 additions & 7 deletions internal/handlers/product/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strconv"

"github.com/SnackLog/database-api-wrapper/internal/database/product"
"github.com/SnackLog/database-api-wrapper/internal/handlers"
"github.com/gin-gonic/gin"
)

Expand All @@ -18,15 +19,15 @@ import (
// @Param q query string true "Search query (min 3 chars)"
// @Param limit query int false "Limit results (default 10, max 100)"
// @Success 200 {object} map[string][]product.Product
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Failure 400 {object} handlers.Error
// @Failure 401 {object} handlers.Error
// @Failure 500 {object} handlers.Error
Comment on lines 19 to +24
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API doc says limit has a max of 100, but the validation rejects limit >= 100 and the error message says it must be less than 100 (i.e., max 99). Update either the docs or the validation/message so they are consistent.

Copilot uses AI. Check for mistakes.
// @Security Bearer
// @Router /products/search [get]
func (p *ProductController) Get(c *gin.Context) {
query := c.Query("q")
if query == "" || len(query) < 3 {
c.JSON(http.StatusBadRequest, gin.H{"error": "Query parameter 'q' is required and must be at least 3 characters long"})
c.JSON(http.StatusBadRequest, handlers.Error{Error: "Query parameter 'q' is required and must be at least 3 characters long"})
return
}

Expand All @@ -40,19 +41,19 @@ func (p *ProductController) Get(c *gin.Context) {
if err != nil {
log.Println(err)
}
c.JSON(http.StatusBadRequest, gin.H{"error": "Query parameter 'limit' must be a positive integer less than 100"})
c.JSON(http.StatusBadRequest, handlers.Error{Error: "Query parameter 'limit' must be a positive integer less than 100"})
return
}

products, err := product.SearchProductByName(p.DB, query, int(limit))
if err != nil {
log.Println(err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
c.JSON(http.StatusInternalServerError, handlers.Error{Error: err.Error()})
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 500 response body includes the raw internal error string (err.Error()), which can leak implementation/database details to clients. Consider returning a generic message (and optionally a stable error code) while keeping the detailed error only in logs.

Suggested change
c.JSON(http.StatusInternalServerError, handlers.Error{Error: err.Error()})
c.JSON(http.StatusInternalServerError, handlers.Error{Error: "internal server error"})

Copilot uses AI. Check for mistakes.
return
}
if products == nil {
log.Println("Products was nil?!")
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "products was nil."})
c.AbortWithStatusJSON(http.StatusInternalServerError, handlers.Error{Error: "products was nil."})
return
}

Expand Down
15 changes: 8 additions & 7 deletions internal/handlers/product/getId.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/http"

"github.com/SnackLog/database-api-wrapper/internal/database/product"
"github.com/SnackLog/database-api-wrapper/internal/handlers"
"github.com/gin-gonic/gin"
)

Expand All @@ -16,28 +17,28 @@ import (
// @Produce json
// @Param id path string true "Product ID"
// @Success 200 {object} map[string]product.Product
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Failure 400 {object} handlers.Error
// @Failure 401 {object} handlers.Error
// @Failure 404 {object} handlers.Error
// @Failure 500 {object} handlers.Error
// @Security Bearer
// @Router /products/{id} [get]
func (p *ProductController) GetID(c *gin.Context) {
id := c.Param("id")
if id == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "ID is required"})
c.JSON(http.StatusBadRequest, handlers.Error{Error: "ID is required"})
return
}

product, err := product.GetProductByID(p.DB, id)
if err != nil {
log.Println(err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
c.JSON(http.StatusInternalServerError, handlers.Error{Error: err.Error()})
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 500 response body includes the raw internal error string (err.Error()), which can leak implementation/database details to clients. Consider returning a generic message (and optionally a stable error code) while keeping the detailed error only in logs.

Suggested change
c.JSON(http.StatusInternalServerError, handlers.Error{Error: err.Error()})
c.JSON(http.StatusInternalServerError, handlers.Error{Error: "Internal server error"})

Copilot uses AI. Check for mistakes.
return
}

if product == nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Product not found"})
c.JSON(http.StatusNotFound, handlers.Error{Error: "Product not found"})
return
}

Expand Down
3 changes: 2 additions & 1 deletion internal/health/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import (
"context"
"net/http"

"github.com/SnackLog/database-api-wrapper/internal/handlers"
"github.com/gin-gonic/gin"
)

func (hc *HealthController) Get(c *gin.Context) {
err := hc.DB.Ping(context.TODO(), nil)
if err != nil {
c.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{"error": "Database connection is down"})
c.AbortWithStatusJSON(http.StatusServiceUnavailable, handlers.Error{Error: "Database connection is down"})
return
}
c.Status(http.StatusOK)
Expand Down
Loading