init: first steps
This commit is contained in:
118
pkg/http/errors.go
Normal file
118
pkg/http/errors.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
)
|
||||
|
||||
type ResponseErr struct {
|
||||
Message string `json:"message"`
|
||||
Trace string `json:"trace"`
|
||||
Details map[string]any `json:"details"`
|
||||
}
|
||||
|
||||
type ResponseErrReadyToSend interface {
|
||||
Send(http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type ResponseErrBuilder interface {
|
||||
WithDetails(map[string]any) ResponseErrBuilder
|
||||
WithMessage(string) ResponseErrBuilder
|
||||
WithStatusCode(int) ResponseErrBuilder
|
||||
WithTrace(string) ResponseErrBuilder
|
||||
Ready() ResponseErrReadyToSend
|
||||
Send(http.ResponseWriter, *http.Request) error
|
||||
}
|
||||
|
||||
type responseErrBuilder struct {
|
||||
details map[string]any
|
||||
message string
|
||||
status int
|
||||
trace string
|
||||
|
||||
ready *ResponseErr
|
||||
}
|
||||
|
||||
type readyResponseErr struct {
|
||||
builder responseErrBuilder
|
||||
}
|
||||
|
||||
func (r readyResponseErr) Send(response http.ResponseWriter) error {
|
||||
format, err := json.Marshal(r.builder.ready)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.builder.status == 0 {
|
||||
r.builder.status = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
response.WriteHeader(r.builder.status)
|
||||
|
||||
_, err = response.Write(format)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (r responseErrBuilder) WithTrace(s string) ResponseErrBuilder {
|
||||
r.trace = s
|
||||
return r
|
||||
}
|
||||
|
||||
func (r responseErrBuilder) WithStatusCode(i int) ResponseErrBuilder {
|
||||
r.status = i
|
||||
return r
|
||||
}
|
||||
|
||||
func NewResponseErrBuilder() ResponseErrBuilder {
|
||||
return &responseErrBuilder{}
|
||||
}
|
||||
|
||||
func (r responseErrBuilder) WithDetails(m map[string]any) ResponseErrBuilder {
|
||||
r.details = m
|
||||
return r
|
||||
}
|
||||
|
||||
func (r responseErrBuilder) WithMessage(s string) ResponseErrBuilder {
|
||||
r.message = s
|
||||
return r
|
||||
}
|
||||
|
||||
func (r responseErrBuilder) Ready() ResponseErrReadyToSend {
|
||||
r.ready = &ResponseErr{
|
||||
Message: r.message,
|
||||
Trace: r.trace,
|
||||
Details: r.details,
|
||||
}
|
||||
|
||||
return readyResponseErr{
|
||||
builder: r,
|
||||
}
|
||||
}
|
||||
|
||||
func (r responseErrBuilder) Send(response http.ResponseWriter, request *http.Request) error {
|
||||
if r.ready == nil {
|
||||
r.ready = &ResponseErr{
|
||||
Message: r.message,
|
||||
Trace: middleware.GetReqID(request.Context()),
|
||||
Details: r.details,
|
||||
}
|
||||
}
|
||||
|
||||
format, err := json.Marshal(r.ready)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.status == 0 {
|
||||
r.status = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
response.WriteHeader(r.status)
|
||||
|
||||
_, err = response.Write(format)
|
||||
|
||||
return err
|
||||
}
|
||||
46
pkg/http/extract.go
Normal file
46
pkg/http/extract.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func ExtractLimitOffset(r *http.Request) (int, int, ResponseErrReadyToSend) {
|
||||
limit, offset := r.URL.Query().Get("limit"), r.URL.Query().Get("offset")
|
||||
|
||||
if limit == "" {
|
||||
limit = "20"
|
||||
}
|
||||
|
||||
if offset == "" {
|
||||
offset = "0"
|
||||
}
|
||||
|
||||
limitInt, err := strconv.Atoi(limit)
|
||||
if err != nil {
|
||||
writeErr := NewResponseErrBuilder().
|
||||
WithMessage("Incorrect limit parameter").
|
||||
WithDetails(map[string]interface{}{
|
||||
"err": err.Error(),
|
||||
}).
|
||||
WithStatusCode(http.StatusBadRequest).
|
||||
Ready()
|
||||
|
||||
return 0, 0, writeErr
|
||||
}
|
||||
|
||||
offsetInt, err := strconv.Atoi(offset)
|
||||
if err != nil {
|
||||
writeErr := NewResponseErrBuilder().
|
||||
WithMessage("Incorrect offset parameter").
|
||||
WithDetails(map[string]interface{}{
|
||||
"err": err.Error(),
|
||||
}).
|
||||
WithStatusCode(http.StatusBadRequest).
|
||||
Ready()
|
||||
|
||||
return 0, 0, writeErr
|
||||
}
|
||||
|
||||
return limitInt, offsetInt, nil
|
||||
}
|
||||
19
pkg/http/response.go
Normal file
19
pkg/http/response.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func JSON(w http.ResponseWriter, i any, httpCode int) error {
|
||||
response, err := json.Marshal(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(httpCode)
|
||||
_, err = w.Write(response)
|
||||
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user