2023-07-18 14:40:10 +02:00
|
|
|
package ginext
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"github.com/gin-gonic/gin"
|
2023-07-24 11:11:15 +02:00
|
|
|
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
|
2023-07-18 14:40:10 +02:00
|
|
|
json "gogs.mikescher.com/BlackForestBytes/goext/gojson"
|
|
|
|
)
|
|
|
|
|
2023-07-24 14:16:02 +02:00
|
|
|
type headerval struct {
|
|
|
|
Key string
|
|
|
|
Val string
|
|
|
|
}
|
|
|
|
|
2023-07-18 14:40:10 +02:00
|
|
|
type HTTPResponse interface {
|
|
|
|
Write(g *gin.Context)
|
2023-07-24 14:16:02 +02:00
|
|
|
WithHeader(k string, v string) HTTPResponse
|
2023-12-02 13:15:19 +01:00
|
|
|
IsSuccess() bool
|
2023-07-18 14:40:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type jsonHTTPResponse struct {
|
|
|
|
statusCode int
|
|
|
|
data any
|
2023-07-24 14:16:02 +02:00
|
|
|
headers []headerval
|
2023-07-18 14:40:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (j jsonHTTPResponse) Write(g *gin.Context) {
|
2023-07-24 14:16:02 +02:00
|
|
|
for _, v := range j.headers {
|
|
|
|
g.Header(v.Key, v.Val)
|
|
|
|
}
|
2023-10-05 12:00:51 +02:00
|
|
|
var f *string
|
|
|
|
if jsonfilter := g.GetString("goext.jsonfilter"); jsonfilter != "" {
|
|
|
|
f = &jsonfilter
|
|
|
|
}
|
|
|
|
g.Render(j.statusCode, json.GoJsonRender{Data: j.data, NilSafeSlices: true, NilSafeMaps: true, Filter: f})
|
2023-07-18 14:40:10 +02:00
|
|
|
}
|
|
|
|
|
2023-07-24 14:16:02 +02:00
|
|
|
func (j jsonHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
|
|
j.headers = append(j.headers, headerval{k, v})
|
|
|
|
return j
|
|
|
|
}
|
|
|
|
|
2023-12-02 13:15:19 +01:00
|
|
|
func (j jsonHTTPResponse) IsSuccess() bool {
|
|
|
|
return j.statusCode >= 200 && j.statusCode <= 399
|
|
|
|
}
|
|
|
|
|
2023-07-18 14:40:10 +02:00
|
|
|
type emptyHTTPResponse struct {
|
|
|
|
statusCode int
|
2023-07-24 14:16:02 +02:00
|
|
|
headers []headerval
|
2023-07-18 14:40:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (j emptyHTTPResponse) Write(g *gin.Context) {
|
2023-07-24 14:16:02 +02:00
|
|
|
for _, v := range j.headers {
|
|
|
|
g.Header(v.Key, v.Val)
|
|
|
|
}
|
2023-07-18 14:40:10 +02:00
|
|
|
g.Status(j.statusCode)
|
|
|
|
}
|
|
|
|
|
2023-07-24 14:16:02 +02:00
|
|
|
func (j emptyHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
|
|
j.headers = append(j.headers, headerval{k, v})
|
|
|
|
return j
|
|
|
|
}
|
|
|
|
|
2023-12-02 13:15:19 +01:00
|
|
|
func (j emptyHTTPResponse) IsSuccess() bool {
|
|
|
|
return j.statusCode >= 200 && j.statusCode <= 399
|
|
|
|
}
|
|
|
|
|
2023-07-18 14:40:10 +02:00
|
|
|
type textHTTPResponse struct {
|
|
|
|
statusCode int
|
|
|
|
data string
|
2023-07-24 14:16:02 +02:00
|
|
|
headers []headerval
|
2023-07-18 14:40:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (j textHTTPResponse) Write(g *gin.Context) {
|
2023-07-24 14:16:02 +02:00
|
|
|
for _, v := range j.headers {
|
|
|
|
g.Header(v.Key, v.Val)
|
|
|
|
}
|
2023-07-18 14:40:10 +02:00
|
|
|
g.String(j.statusCode, "%s", j.data)
|
|
|
|
}
|
|
|
|
|
2023-07-24 14:16:02 +02:00
|
|
|
func (j textHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
|
|
j.headers = append(j.headers, headerval{k, v})
|
|
|
|
return j
|
|
|
|
}
|
|
|
|
|
2023-12-02 13:15:19 +01:00
|
|
|
func (j textHTTPResponse) IsSuccess() bool {
|
|
|
|
return j.statusCode >= 200 && j.statusCode <= 399
|
|
|
|
}
|
|
|
|
|
2023-07-18 14:40:10 +02:00
|
|
|
type dataHTTPResponse struct {
|
|
|
|
statusCode int
|
|
|
|
data []byte
|
|
|
|
contentType string
|
2023-07-24 14:16:02 +02:00
|
|
|
headers []headerval
|
2023-07-18 14:40:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (j dataHTTPResponse) Write(g *gin.Context) {
|
2023-07-24 14:16:02 +02:00
|
|
|
for _, v := range j.headers {
|
|
|
|
g.Header(v.Key, v.Val)
|
|
|
|
}
|
2023-07-18 14:40:10 +02:00
|
|
|
g.Data(j.statusCode, j.contentType, j.data)
|
|
|
|
}
|
|
|
|
|
2023-07-24 14:16:02 +02:00
|
|
|
func (j dataHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
|
|
j.headers = append(j.headers, headerval{k, v})
|
|
|
|
return j
|
|
|
|
}
|
|
|
|
|
2023-12-02 13:15:19 +01:00
|
|
|
func (j dataHTTPResponse) IsSuccess() bool {
|
|
|
|
return j.statusCode >= 200 && j.statusCode <= 399
|
|
|
|
}
|
|
|
|
|
2023-07-18 14:40:10 +02:00
|
|
|
type fileHTTPResponse struct {
|
|
|
|
mimetype string
|
|
|
|
filepath string
|
|
|
|
filename *string
|
2023-07-24 14:16:02 +02:00
|
|
|
headers []headerval
|
2023-07-18 14:40:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (j fileHTTPResponse) Write(g *gin.Context) {
|
|
|
|
g.Header("Content-Type", j.mimetype) // if we don't set it here gin does weird file-sniffing later...
|
|
|
|
if j.filename != nil {
|
|
|
|
g.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", *j.filename))
|
|
|
|
|
|
|
|
}
|
2023-07-24 14:16:02 +02:00
|
|
|
for _, v := range j.headers {
|
|
|
|
g.Header(v.Key, v.Val)
|
|
|
|
}
|
2023-07-18 14:40:10 +02:00
|
|
|
g.File(j.filepath)
|
|
|
|
}
|
|
|
|
|
2023-07-24 14:16:02 +02:00
|
|
|
func (j fileHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
|
|
j.headers = append(j.headers, headerval{k, v})
|
|
|
|
return j
|
|
|
|
}
|
|
|
|
|
2023-12-02 13:15:19 +01:00
|
|
|
func (j fileHTTPResponse) IsSuccess() bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-08-06 19:10:31 +02:00
|
|
|
type downloadDataHTTPResponse struct {
|
|
|
|
statusCode int
|
|
|
|
mimetype string
|
|
|
|
data []byte
|
|
|
|
filename *string
|
|
|
|
headers []headerval
|
|
|
|
}
|
|
|
|
|
|
|
|
func (j downloadDataHTTPResponse) Write(g *gin.Context) {
|
|
|
|
g.Header("Content-Type", j.mimetype) // if we don't set it here gin does weird file-sniffing later...
|
|
|
|
if j.filename != nil {
|
|
|
|
g.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", *j.filename))
|
|
|
|
|
|
|
|
}
|
|
|
|
for _, v := range j.headers {
|
|
|
|
g.Header(v.Key, v.Val)
|
|
|
|
}
|
|
|
|
g.Data(j.statusCode, j.mimetype, j.data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (j downloadDataHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
|
|
j.headers = append(j.headers, headerval{k, v})
|
|
|
|
return j
|
|
|
|
}
|
|
|
|
|
2023-12-02 13:15:19 +01:00
|
|
|
func (j downloadDataHTTPResponse) IsSuccess() bool {
|
|
|
|
return j.statusCode >= 200 && j.statusCode <= 399
|
|
|
|
}
|
|
|
|
|
2023-07-18 15:23:32 +02:00
|
|
|
type redirectHTTPResponse struct {
|
|
|
|
statusCode int
|
|
|
|
url string
|
2023-07-24 14:16:02 +02:00
|
|
|
headers []headerval
|
2023-07-18 15:23:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (j redirectHTTPResponse) Write(g *gin.Context) {
|
|
|
|
g.Redirect(j.statusCode, j.url)
|
|
|
|
}
|
|
|
|
|
2023-07-24 14:16:02 +02:00
|
|
|
func (j redirectHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
|
|
j.headers = append(j.headers, headerval{k, v})
|
|
|
|
return j
|
|
|
|
}
|
|
|
|
|
2023-12-02 13:15:19 +01:00
|
|
|
func (j redirectHTTPResponse) IsSuccess() bool {
|
|
|
|
return j.statusCode >= 200 && j.statusCode <= 399
|
|
|
|
}
|
|
|
|
|
2023-07-24 11:11:15 +02:00
|
|
|
type jsonAPIErrResponse struct {
|
2023-07-24 14:16:02 +02:00
|
|
|
err *exerr.ExErr
|
|
|
|
headers []headerval
|
2023-07-24 11:11:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (j jsonAPIErrResponse) Write(g *gin.Context) {
|
|
|
|
j.err.Output(g)
|
|
|
|
}
|
|
|
|
|
2023-07-24 14:16:02 +02:00
|
|
|
func (j jsonAPIErrResponse) WithHeader(k string, v string) HTTPResponse {
|
|
|
|
j.headers = append(j.headers, headerval{k, v})
|
|
|
|
return j
|
|
|
|
}
|
|
|
|
|
2023-12-02 13:15:19 +01:00
|
|
|
func (j jsonAPIErrResponse) IsSuccess() bool {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-07-18 14:40:10 +02:00
|
|
|
func Status(sc int) HTTPResponse {
|
|
|
|
return &emptyHTTPResponse{statusCode: sc}
|
|
|
|
}
|
|
|
|
|
|
|
|
func JSON(sc int, data any) HTTPResponse {
|
|
|
|
return &jsonHTTPResponse{statusCode: sc, data: data}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Data(sc int, contentType string, data []byte) HTTPResponse {
|
|
|
|
return &dataHTTPResponse{statusCode: sc, contentType: contentType, data: data}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Text(sc int, data string) HTTPResponse {
|
|
|
|
return &textHTTPResponse{statusCode: sc, data: data}
|
|
|
|
}
|
|
|
|
|
|
|
|
func File(mimetype string, filepath string) HTTPResponse {
|
|
|
|
return &fileHTTPResponse{mimetype: mimetype, filepath: filepath}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Download(mimetype string, filepath string, filename string) HTTPResponse {
|
|
|
|
return &fileHTTPResponse{mimetype: mimetype, filepath: filepath, filename: &filename}
|
|
|
|
}
|
|
|
|
|
2023-08-06 19:11:59 +02:00
|
|
|
func DownloadData(status int, mimetype string, filename string, data []byte) HTTPResponse {
|
|
|
|
return &downloadDataHTTPResponse{statusCode: status, mimetype: mimetype, data: data, filename: &filename}
|
2023-08-06 19:10:31 +02:00
|
|
|
}
|
|
|
|
|
2023-07-18 15:23:32 +02:00
|
|
|
func Redirect(sc int, newURL string) HTTPResponse {
|
|
|
|
return &redirectHTTPResponse{statusCode: sc, url: newURL}
|
|
|
|
}
|
|
|
|
|
2023-07-25 10:51:14 +02:00
|
|
|
func Error(e error) HTTPResponse {
|
2023-07-24 11:11:15 +02:00
|
|
|
return &jsonAPIErrResponse{
|
|
|
|
err: exerr.FromError(e),
|
|
|
|
}
|
2023-07-18 14:40:10 +02:00
|
|
|
}
|
|
|
|
|
2023-07-25 10:51:14 +02:00
|
|
|
func ErrWrap(e error, errorType exerr.ErrorType, msg string) HTTPResponse {
|
|
|
|
return &jsonAPIErrResponse{
|
2023-08-22 10:36:35 +02:00
|
|
|
err: exerr.FromError(exerr.Wrap(e, msg).WithType(errorType).Build()),
|
2023-07-25 10:51:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func NotImplemented() HTTPResponse {
|
|
|
|
return Error(exerr.New(exerr.TypeNotImplemented, "").Build())
|
2023-07-18 14:40:10 +02:00
|
|
|
}
|