diff --git a/auth_context.go b/auth_context.go deleted file mode 100644 index b2c68b6..0000000 --- a/auth_context.go +++ /dev/null @@ -1,6 +0,0 @@ -package ginboot - -type AuthContext struct { - UserId string - Role string -} diff --git a/api.go b/context.go similarity index 64% rename from api.go rename to context.go index cdd6613..1aa2dc9 100644 --- a/api.go +++ b/context.go @@ -8,7 +8,26 @@ import ( "strings" ) -func GetAuthContext(c *gin.Context) (AuthContext, error) { +type AuthContext struct { + UserID string + UserEmail string + Roles []string + Claims map[string]interface{} +} + +type Context struct { + *gin.Context + authContext *AuthContext +} + +func NewContext(c *gin.Context) *Context { + return &Context{ + Context: c, + } +} + +// GetAuthContext returns the current auth context +func (c *Context) GetAuthContext() (AuthContext, error) { userId, exists := c.Get("user_id") if !exists { c.AbortWithStatus(http.StatusUnauthorized) @@ -20,25 +39,20 @@ func GetAuthContext(c *gin.Context) (AuthContext, error) { return AuthContext{}, errors.New("operation not permitted") } return AuthContext{ - UserId: userId.(string), - Role: role.(string), + UserID: userId.(string), + Roles: []string{role.(string)}, }, nil } -func BuildAuthRequestContext[T interface{}](c *gin.Context) (T, AuthContext, error) { - request, err := BuildRequest[T](c) - if err != nil { - return request, AuthContext{}, err - } - authContext, err := GetAuthContext(c) - if err != nil { +func (c *Context) GetRequest(request interface{}) error { + if err := c.ShouldBind(request); err != nil { c.AbortWithStatus(http.StatusBadRequest) - return request, AuthContext{}, err + return errors.New("bad request: " + err.Error()) } - return request, authContext, nil + return nil } -func BuildPageRequest(c *gin.Context) PageRequest { +func (c *Context) GetPageRequest() PageRequest { pageString := c.DefaultQuery("page", "1") sizeString := c.DefaultQuery("size", "10") sortString := c.DefaultQuery("sort", "_id,asc") @@ -70,12 +84,3 @@ func BuildPageRequest(c *gin.Context) PageRequest { return PageRequest{Page: int(page), Size: int(size), Sort: sort} } - -func BuildRequest[T interface{}](c *gin.Context) (T, error) { - var request T - if c.ShouldBindJSON(&request) != nil { - c.AbortWithStatus(http.StatusBadRequest) - return request, errors.New("bad request") - } - return request, nil -} diff --git a/example/internal/controller/post_controller.go b/example/internal/controller/post_controller.go index 933409e..6e27dfc 100644 --- a/example/internal/controller/post_controller.go +++ b/example/internal/controller/post_controller.go @@ -37,7 +37,8 @@ func (c *PostController) Register(group *ginboot.ControllerGroup) { } } -func (c *PostController) CreatePost(ctx *gin.Context) { +func (c *PostController) CreatePost(ctx *ginboot.Context) { + ctx.BuildRequest() var post model.Post if err := ctx.ShouldBindJSON(&post); err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) @@ -53,7 +54,7 @@ func (c *PostController) CreatePost(ctx *gin.Context) { ctx.JSON(http.StatusCreated, createdPost) } -func (c *PostController) GetPost(ctx *gin.Context) { +func (c *PostController) GetPost(ctx *ginboot.Context) { id := ctx.Param("id") post, err := c.postService.GetPostById(id) if err != nil { @@ -64,7 +65,7 @@ func (c *PostController) GetPost(ctx *gin.Context) { ctx.JSON(http.StatusOK, post) } -func (c *PostController) UpdatePost(ctx *gin.Context) { +func (c *PostController) UpdatePost(ctx *ginboot.Context) { id := ctx.Param("id") var post model.Post if err := ctx.ShouldBindJSON(&post); err != nil { @@ -80,7 +81,7 @@ func (c *PostController) UpdatePost(ctx *gin.Context) { ctx.Status(http.StatusOK) } -func (c *PostController) DeletePost(ctx *gin.Context) { +func (c *PostController) DeletePost(ctx *ginboot.Context) { id := ctx.Param("id") if err := c.postService.DeletePost(id); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) @@ -90,7 +91,7 @@ func (c *PostController) DeletePost(ctx *gin.Context) { ctx.Status(http.StatusOK) } -func (c *PostController) GetPosts(ctx *gin.Context) { +func (c *PostController) GetPosts(ctx *ginboot.Context) { page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1")) size, _ := strconv.Atoi(ctx.DefaultQuery("size", "10")) sortField := ctx.DefaultQuery("sort", "created_at") @@ -108,7 +109,7 @@ func (c *PostController) GetPosts(ctx *gin.Context) { ctx.JSON(http.StatusOK, posts) } -func (c *PostController) GetPostsByAuthor(ctx *gin.Context) { +func (c *PostController) GetPostsByAuthor(ctx *ginboot.Context) { author := ctx.Param("author") page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1")) size, _ := strconv.Atoi(ctx.DefaultQuery("size", "10")) @@ -122,7 +123,7 @@ func (c *PostController) GetPostsByAuthor(ctx *gin.Context) { ctx.JSON(http.StatusOK, posts) } -func (c *PostController) GetPostsByTags(ctx *gin.Context) { +func (c *PostController) GetPostsByTags(ctx *ginboot.Context) { tagsStr := ctx.Query("tags") tags := strings.Split(tagsStr, ",") page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1")) diff --git a/go.mod b/go.mod index 615914a..c76e6fb 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/docker/go-connections v0.5.0 github.com/gin-contrib/cors v1.7.2 github.com/gin-gonic/gin v1.10.0 + github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/uuid v1.6.0 github.com/stretchr/testify v1.10.0 github.com/testcontainers/testcontainers-go v0.34.0 diff --git a/go.sum b/go.sum index 7d72ee0..7fd7295 100644 --- a/go.sum +++ b/go.sum @@ -109,6 +109,8 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= diff --git a/router.go b/router.go index f50ac38..567c958 100644 --- a/router.go +++ b/router.go @@ -24,46 +24,49 @@ func (s *Server) Group(relativePath string, middleware ...gin.HandlerFunc) *Cont } } +// Handle wraps gin handler to use custom context +func (g *ControllerGroup) Handle(httpMethod, relativePath string, handler func(*Context), middleware ...gin.HandlerFunc) { + wrappedHandler := func(c *gin.Context) { + ctx := NewContext(c) + handler(ctx) + } + handlers := append(middleware, wrappedHandler) + g.group.Handle(httpMethod, relativePath, handlers...) +} + // GET registers a GET route -func (g *ControllerGroup) GET(relativePath string, handler gin.HandlerFunc, middleware ...gin.HandlerFunc) { - handlers := append(middleware, handler) - g.group.GET(relativePath, handlers...) +func (g *ControllerGroup) GET(relativePath string, handler func(*Context), middleware ...gin.HandlerFunc) { + g.Handle("GET", relativePath, handler, middleware...) } // POST registers a POST route -func (g *ControllerGroup) POST(relativePath string, handler gin.HandlerFunc, middleware ...gin.HandlerFunc) { - handlers := append(middleware, handler) - g.group.POST(relativePath, handlers...) +func (g *ControllerGroup) POST(relativePath string, handler func(*Context), middleware ...gin.HandlerFunc) { + g.Handle("POST", relativePath, handler, middleware...) } // PUT registers a PUT route -func (g *ControllerGroup) PUT(relativePath string, handler gin.HandlerFunc, middleware ...gin.HandlerFunc) { - handlers := append(middleware, handler) - g.group.PUT(relativePath, handlers...) +func (g *ControllerGroup) PUT(relativePath string, handler func(*Context), middleware ...gin.HandlerFunc) { + g.Handle("PUT", relativePath, handler, middleware...) } // DELETE registers a DELETE route -func (g *ControllerGroup) DELETE(relativePath string, handler gin.HandlerFunc, middleware ...gin.HandlerFunc) { - handlers := append(middleware, handler) - g.group.DELETE(relativePath, handlers...) +func (g *ControllerGroup) DELETE(relativePath string, handler func(*Context), middleware ...gin.HandlerFunc) { + g.Handle("DELETE", relativePath, handler, middleware...) } // PATCH registers a PATCH route -func (g *ControllerGroup) PATCH(relativePath string, handler gin.HandlerFunc, middleware ...gin.HandlerFunc) { - handlers := append(middleware, handler) - g.group.PATCH(relativePath, handlers...) +func (g *ControllerGroup) PATCH(relativePath string, handler func(*Context), middleware ...gin.HandlerFunc) { + g.Handle("PATCH", relativePath, handler, middleware...) } // OPTIONS registers an OPTIONS route -func (g *ControllerGroup) OPTIONS(relativePath string, handler gin.HandlerFunc, middleware ...gin.HandlerFunc) { - handlers := append(middleware, handler) - g.group.OPTIONS(relativePath, handlers...) +func (g *ControllerGroup) OPTIONS(relativePath string, handler func(*Context), middleware ...gin.HandlerFunc) { + g.Handle("OPTIONS", relativePath, handler, middleware...) } // HEAD registers a HEAD route -func (g *ControllerGroup) HEAD(relativePath string, handler gin.HandlerFunc, middleware ...gin.HandlerFunc) { - handlers := append(middleware, handler) - g.group.HEAD(relativePath, handlers...) +func (g *ControllerGroup) HEAD(relativePath string, handler func(*Context), middleware ...gin.HandlerFunc) { + g.Handle("HEAD", relativePath, handler, middleware...) } // Group creates a new sub-group with the given path and middleware