Compare commits

...

4 Commits

Author SHA1 Message Date
adf32568ee v0.0.199 2023-07-24 17:23:38 +02:00
0cfa159cb1 v0.0.198 2023-07-24 14:16:02 +02:00
0ead99608a v0.0.197 2023-07-24 12:27:06 +02:00
7fe3e66cad v0.0.196 2023-07-24 11:47:47 +02:00
5 changed files with 120 additions and 24 deletions

View File

@@ -52,6 +52,7 @@ func (ee *ExErr) Output(g *gin.Context) {
var baseCat = ee.RecursiveCategory() var baseCat = ee.RecursiveCategory()
var baseType = ee.RecursiveType() var baseType = ee.RecursiveType()
var baseStatuscode = ee.RecursiveStatuscode() var baseStatuscode = ee.RecursiveStatuscode()
var baseMessage = ee.RecursiveMessage()
if baseCat == CatUser { if baseCat == CatUser {
statuscode = http.StatusBadRequest statuscode = http.StatusBadRequest
@@ -69,9 +70,9 @@ func (ee *ExErr) Output(g *gin.Context) {
ginOutput := gin.H{ ginOutput := gin.H{
"errorid": ee.UniqueID, "errorid": ee.UniqueID,
"message": ee.RecursiveMessage(), "message": baseMessage,
"errorcode": ee.RecursiveType(), "errorcode": baseType.Key,
"category": ee.RecursiveCategory(), "category": baseCat.Category,
} }
if pkgconfig.ExtendedGinOutput { if pkgconfig.ExtendedGinOutput {

View File

@@ -2,8 +2,10 @@ package ginext
import ( import (
"context" "context"
"fmt"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/binding"
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
"gogs.mikescher.com/BlackForestBytes/goext/langext" "gogs.mikescher.com/BlackForestBytes/goext/langext"
"runtime/debug" "runtime/debug"
) )
@@ -40,33 +42,55 @@ func (pctx *PreContext) Form(form any) *PreContext {
func (pctx PreContext) Start() (*AppContext, *gin.Context, *HTTPResponse) { func (pctx PreContext) Start() (*AppContext, *gin.Context, *HTTPResponse) {
if pctx.uri != nil { if pctx.uri != nil {
if err := pctx.ginCtx.ShouldBindUri(pctx.uri); err != nil { if err := pctx.ginCtx.ShouldBindUri(pctx.uri); err != nil {
return nil, nil, langext.Ptr(APIError(pctx.ginCtx, commonApiErr.BindFailURI, "Failed to read uri", err)) err = exerr.Wrap(err, "Failed to read uri").
WithType(exerr.TypeBindFailURI).
Str("struct_type", fmt.Sprintf("%T", pctx.uri)).
Build()
return nil, nil, langext.Ptr(APIError(pctx.ginCtx, err))
} }
} }
if pctx.query != nil { if pctx.query != nil {
if err := pctx.ginCtx.ShouldBindQuery(pctx.query); err != nil { if err := pctx.ginCtx.ShouldBindQuery(pctx.query); err != nil {
return nil, nil, langext.Ptr(APIError(pctx.ginCtx, commonApiErr.BindFailQuery, "Failed to read query", err)) err = exerr.Wrap(err, "Failed to read query").
WithType(exerr.TypeBindFailQuery).
Str("struct_type", fmt.Sprintf("%T", pctx.query)).
Build()
return nil, nil, langext.Ptr(APIError(pctx.ginCtx, err))
} }
} }
if pctx.body != nil { if pctx.body != nil {
if pctx.ginCtx.ContentType() == "application/json" { if pctx.ginCtx.ContentType() == "application/json" {
if err := pctx.ginCtx.ShouldBindJSON(pctx.body); err != nil { if err := pctx.ginCtx.ShouldBindJSON(pctx.body); err != nil {
return nil, nil, langext.Ptr(APIError(pctx.ginCtx, commonApiErr.BindFailJSON, "Failed to read body", err)) err = exerr.Wrap(err, "Failed to read json-body").
WithType(exerr.TypeBindFailJSON).
Str("struct_type", fmt.Sprintf("%T", pctx.body)).
Build()
return nil, nil, langext.Ptr(APIError(pctx.ginCtx, err))
} }
} else { } else {
return nil, nil, langext.Ptr(APIError(pctx.ginCtx, commonApiErr.BindFailJSON, "missing JSON body", nil)) err := exerr.New(exerr.TypeBindFailJSON, "missing JSON body").
Str("struct_type", fmt.Sprintf("%T", pctx.body)).
Build()
return nil, nil, langext.Ptr(APIError(pctx.ginCtx, err))
} }
} }
if pctx.form != nil { if pctx.form != nil {
if pctx.ginCtx.ContentType() == "multipart/form-data" { if pctx.ginCtx.ContentType() == "multipart/form-data" {
if err := pctx.ginCtx.ShouldBindWith(pctx.form, binding.Form); err != nil { if err := pctx.ginCtx.ShouldBindWith(pctx.form, binding.Form); err != nil {
return nil, nil, langext.Ptr(APIError(pctx.ginCtx, commonApiErr.BindFailFormData, "Failed to read multipart-form", err)) err = exerr.Wrap(err, "Failed to read multipart-form").
WithType(exerr.TypeBindFailFormData).
Str("struct_type", fmt.Sprintf("%T", pctx.form)).
Build()
return nil, nil, langext.Ptr(APIError(pctx.ginCtx, err))
} }
} else { } else {
return nil, nil, langext.Ptr(APIError(pctx.ginCtx, commonApiErr.BindFailJSON, "missing form body", nil)) err := exerr.New(exerr.TypeBindFailFormData, "missing form body").
Str("struct_type", fmt.Sprintf("%T", pctx.form)).
Build()
return nil, nil, langext.Ptr(APIError(pctx.ginCtx, err))
} }
} }

View File

@@ -7,50 +7,93 @@ import (
json "gogs.mikescher.com/BlackForestBytes/goext/gojson" json "gogs.mikescher.com/BlackForestBytes/goext/gojson"
) )
type headerval struct {
Key string
Val string
}
type HTTPResponse interface { type HTTPResponse interface {
Write(g *gin.Context) Write(g *gin.Context)
WithHeader(k string, v string) HTTPResponse
} }
type jsonHTTPResponse struct { type jsonHTTPResponse struct {
statusCode int statusCode int
data any data any
headers []headerval
} }
func (j jsonHTTPResponse) Write(g *gin.Context) { func (j jsonHTTPResponse) Write(g *gin.Context) {
for _, v := range j.headers {
g.Header(v.Key, v.Val)
}
g.Render(j.statusCode, json.GoJsonRender{Data: j.data, NilSafeSlices: true, NilSafeMaps: true}) g.Render(j.statusCode, json.GoJsonRender{Data: j.data, NilSafeSlices: true, NilSafeMaps: true})
} }
func (j jsonHTTPResponse) WithHeader(k string, v string) HTTPResponse {
j.headers = append(j.headers, headerval{k, v})
return j
}
type emptyHTTPResponse struct { type emptyHTTPResponse struct {
statusCode int statusCode int
headers []headerval
} }
func (j emptyHTTPResponse) Write(g *gin.Context) { func (j emptyHTTPResponse) Write(g *gin.Context) {
for _, v := range j.headers {
g.Header(v.Key, v.Val)
}
g.Status(j.statusCode) g.Status(j.statusCode)
} }
func (j emptyHTTPResponse) WithHeader(k string, v string) HTTPResponse {
j.headers = append(j.headers, headerval{k, v})
return j
}
type textHTTPResponse struct { type textHTTPResponse struct {
statusCode int statusCode int
data string data string
headers []headerval
} }
func (j textHTTPResponse) Write(g *gin.Context) { func (j textHTTPResponse) Write(g *gin.Context) {
for _, v := range j.headers {
g.Header(v.Key, v.Val)
}
g.String(j.statusCode, "%s", j.data) g.String(j.statusCode, "%s", j.data)
} }
func (j textHTTPResponse) WithHeader(k string, v string) HTTPResponse {
j.headers = append(j.headers, headerval{k, v})
return j
}
type dataHTTPResponse struct { type dataHTTPResponse struct {
statusCode int statusCode int
data []byte data []byte
contentType string contentType string
headers []headerval
} }
func (j dataHTTPResponse) Write(g *gin.Context) { func (j dataHTTPResponse) Write(g *gin.Context) {
for _, v := range j.headers {
g.Header(v.Key, v.Val)
}
g.Data(j.statusCode, j.contentType, j.data) g.Data(j.statusCode, j.contentType, j.data)
} }
func (j dataHTTPResponse) WithHeader(k string, v string) HTTPResponse {
j.headers = append(j.headers, headerval{k, v})
return j
}
type fileHTTPResponse struct { type fileHTTPResponse struct {
mimetype string mimetype string
filepath string filepath string
filename *string filename *string
headers []headerval
} }
func (j fileHTTPResponse) Write(g *gin.Context) { func (j fileHTTPResponse) Write(g *gin.Context) {
@@ -59,26 +102,46 @@ func (j fileHTTPResponse) Write(g *gin.Context) {
g.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", *j.filename)) g.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", *j.filename))
} }
for _, v := range j.headers {
g.Header(v.Key, v.Val)
}
g.File(j.filepath) g.File(j.filepath)
} }
func (j fileHTTPResponse) WithHeader(k string, v string) HTTPResponse {
j.headers = append(j.headers, headerval{k, v})
return j
}
type redirectHTTPResponse struct { type redirectHTTPResponse struct {
statusCode int statusCode int
url string url string
headers []headerval
} }
func (j redirectHTTPResponse) Write(g *gin.Context) { func (j redirectHTTPResponse) Write(g *gin.Context) {
g.Redirect(j.statusCode, j.url) g.Redirect(j.statusCode, j.url)
} }
func (j redirectHTTPResponse) WithHeader(k string, v string) HTTPResponse {
j.headers = append(j.headers, headerval{k, v})
return j
}
type jsonAPIErrResponse struct { type jsonAPIErrResponse struct {
err *exerr.ExErr err *exerr.ExErr
headers []headerval
} }
func (j jsonAPIErrResponse) Write(g *gin.Context) { func (j jsonAPIErrResponse) Write(g *gin.Context) {
j.err.Output(g) j.err.Output(g)
} }
func (j jsonAPIErrResponse) WithHeader(k string, v string) HTTPResponse {
j.headers = append(j.headers, headerval{k, v})
return j
}
func Status(sc int) HTTPResponse { func Status(sc int) HTTPResponse {
return &emptyHTTPResponse{statusCode: sc} return &emptyHTTPResponse{statusCode: sc}
} }

View File

@@ -2,6 +2,7 @@ package ginext
import ( import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"net/http" "net/http"
) )
@@ -12,8 +13,9 @@ var anyMethods = []string{
} }
type GinRoutesWrapper struct { type GinRoutesWrapper struct {
wrapper *GinWrapper wrapper *GinWrapper
routes gin.IRouter routes gin.IRouter
defaultHandler []gin.HandlerFunc
} }
type GinRouteBuilder struct { type GinRouteBuilder struct {
@@ -29,43 +31,49 @@ func (w *GinWrapper) Routes() *GinRoutesWrapper {
} }
func (w *GinRoutesWrapper) Group(relativePath string) *GinRoutesWrapper { func (w *GinRoutesWrapper) Group(relativePath string) *GinRoutesWrapper {
return &GinRoutesWrapper{wrapper: w.wrapper, routes: w.routes.Group(relativePath)} return &GinRoutesWrapper{wrapper: w.wrapper, routes: w.routes.Group(relativePath), defaultHandler: langext.ArrCopy(w.defaultHandler)}
}
func (w *GinRoutesWrapper) Use(middleware ...gin.HandlerFunc) *GinRoutesWrapper {
defHandler := langext.ArrCopy(w.defaultHandler)
defHandler = append(defHandler, middleware...)
return &GinRoutesWrapper{wrapper: w.wrapper, routes: w.routes, defaultHandler: defHandler}
} }
func (w *GinRoutesWrapper) GET(relativePath string) *GinRouteBuilder { func (w *GinRoutesWrapper) GET(relativePath string) *GinRouteBuilder {
return &GinRouteBuilder{routes: w, methods: []string{http.MethodGet}, relPath: relativePath, handlers: make([]gin.HandlerFunc, 0)} return &GinRouteBuilder{routes: w, methods: []string{http.MethodGet}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)}
} }
func (w *GinRoutesWrapper) POST(relativePath string) *GinRouteBuilder { func (w *GinRoutesWrapper) POST(relativePath string) *GinRouteBuilder {
return &GinRouteBuilder{routes: w, methods: []string{http.MethodPost}, relPath: relativePath, handlers: make([]gin.HandlerFunc, 0)} return &GinRouteBuilder{routes: w, methods: []string{http.MethodPost}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)}
} }
func (w *GinRoutesWrapper) DELETE(relativePath string) *GinRouteBuilder { func (w *GinRoutesWrapper) DELETE(relativePath string) *GinRouteBuilder {
return &GinRouteBuilder{routes: w, methods: []string{http.MethodDelete}, relPath: relativePath, handlers: make([]gin.HandlerFunc, 0)} return &GinRouteBuilder{routes: w, methods: []string{http.MethodDelete}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)}
} }
func (w *GinRoutesWrapper) PATCH(relativePath string) *GinRouteBuilder { func (w *GinRoutesWrapper) PATCH(relativePath string) *GinRouteBuilder {
return &GinRouteBuilder{routes: w, methods: []string{http.MethodPatch}, relPath: relativePath, handlers: make([]gin.HandlerFunc, 0)} return &GinRouteBuilder{routes: w, methods: []string{http.MethodPatch}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)}
} }
func (w *GinRoutesWrapper) PUT(relativePath string) *GinRouteBuilder { func (w *GinRoutesWrapper) PUT(relativePath string) *GinRouteBuilder {
return &GinRouteBuilder{routes: w, methods: []string{http.MethodPut}, relPath: relativePath, handlers: make([]gin.HandlerFunc, 0)} return &GinRouteBuilder{routes: w, methods: []string{http.MethodPut}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)}
} }
func (w *GinRoutesWrapper) OPTIONS(relativePath string) *GinRouteBuilder { func (w *GinRoutesWrapper) OPTIONS(relativePath string) *GinRouteBuilder {
return &GinRouteBuilder{routes: w, methods: []string{http.MethodOptions}, relPath: relativePath, handlers: make([]gin.HandlerFunc, 0)} return &GinRouteBuilder{routes: w, methods: []string{http.MethodOptions}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)}
} }
func (w *GinRoutesWrapper) HEAD(relativePath string) *GinRouteBuilder { func (w *GinRoutesWrapper) HEAD(relativePath string) *GinRouteBuilder {
return &GinRouteBuilder{routes: w, methods: []string{http.MethodHead}, relPath: relativePath, handlers: make([]gin.HandlerFunc, 0)} return &GinRouteBuilder{routes: w, methods: []string{http.MethodHead}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)}
} }
func (w *GinRoutesWrapper) COUNT(relativePath string) *GinRouteBuilder { func (w *GinRoutesWrapper) COUNT(relativePath string) *GinRouteBuilder {
return &GinRouteBuilder{routes: w, methods: []string{"COUNT"}, relPath: relativePath, handlers: make([]gin.HandlerFunc, 0)} return &GinRouteBuilder{routes: w, methods: []string{"COUNT"}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)}
} }
func (w *GinRoutesWrapper) Any(relativePath string) *GinRouteBuilder { func (w *GinRoutesWrapper) Any(relativePath string) *GinRouteBuilder {
return &GinRouteBuilder{routes: w, methods: anyMethods, relPath: relativePath, handlers: make([]gin.HandlerFunc, 0)} return &GinRouteBuilder{routes: w, methods: anyMethods, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)}
} }
func (w *GinRouteBuilder) Use(middleware ...gin.HandlerFunc) *GinRouteBuilder { func (w *GinRouteBuilder) Use(middleware ...gin.HandlerFunc) *GinRouteBuilder {

View File

@@ -1,5 +1,5 @@
package goext package goext
const GoextVersion = "0.0.195" const GoextVersion = "0.0.199"
const GoextVersionTimestamp = "2023-07-24T11:42:52+0200" const GoextVersionTimestamp = "2023-07-24T17:23:38+0200"