diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..27e432e --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# IDE folders +/.idea +/.vscode + +# Environment variables +/**/*.env + +# Executable files +/**/*.exe + +# Private and public keys +/**/*.ed +/**/*.pub +/**/*.pem + +# Commands +/**/*.cmd +/**/*.sh +/**/*.bat \ No newline at end of file diff --git a/go.mod b/go.mod index 9fcbbb7..86d519a 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,7 @@ module github.com/ralvarezdev/go-net go 1.23.4 + +require github.com/ralvarezdev/go-flags v0.2.1 + +require github.com/ralvarezdev/go-logger v0.2.1 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..9b93ff0 --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/ralvarezdev/go-flags v0.2.1 h1:zLhEZcb8jaaq5y+Gh7ot1NRaBLKvl0zyNA4st7dT5p0= +github.com/ralvarezdev/go-flags v0.2.1/go.mod h1:pYw9H7NJ07Y5asZDC/EI5bpBLR0kdL2ISsh6X5ws+3s= +github.com/ralvarezdev/go-logger v0.1.0 h1:i2AI1nlxU6Hizvk75Vc8wtFydiVrqIeeRbJwiuO/69A= +github.com/ralvarezdev/go-logger v0.1.0/go.mod h1:v5OvFrkS+wsYNTCVegXWiRhBtcYrQJr4LDMDntvpAos= +github.com/ralvarezdev/go-logger v0.2.1 h1:DamvM2hbiJlxlQ+3pd2yNWowSWm7XBFVjJPg74s+/t0= +github.com/ralvarezdev/go-logger v0.2.1/go.mod h1:v5OvFrkS+wsYNTCVegXWiRhBtcYrQJr4LDMDntvpAos= diff --git a/http/constants.go b/http/constants.go new file mode 100644 index 0000000..0f8d764 --- /dev/null +++ b/http/constants.go @@ -0,0 +1,10 @@ +package http + +import ( + "net/http" +) + +var ( + InternalServerError = http.StatusText(http.StatusInternalServerError) + BadRequest = http.StatusText(http.StatusBadRequest) +) diff --git a/http/json/data.go b/http/json/data.go new file mode 100644 index 0000000..0d05d5f --- /dev/null +++ b/http/json/data.go @@ -0,0 +1,47 @@ +package json + +import ( + goflagsmode "github.com/ralvarezdev/go-flags/mode" + gonethttp "github.com/ralvarezdev/go-net/http" + "net/http" + "reflect" +) + +// checkJSONData checks if the given JSON data is nil or if the reflected data is not a pointer +func checkJSONData( + w http.ResponseWriter, + data interface{}, + mode *goflagsmode.Flag, +) error { + // Check if data is nil + if data == nil { + return handleDataTypeError(w, ErrNilJSONData, mode) + } + + // Check if the reflected data is a pointer + if reflect.ValueOf(data).Kind() != reflect.Ptr { + return handleDataTypeError(w, ErrJSONDataMustBeAPointer, mode) + } + return nil +} + +// handleDataTypeError handles the data type error +func handleDataTypeError( + w http.ResponseWriter, + err error, + mode *goflagsmode.Flag, +) error { + if mode != nil && mode.IsDebug() { + http.Error( + w, + err.Error(), + http.StatusInternalServerError, + ) + } + http.Error( + w, + gonethttp.InternalServerError, + http.StatusInternalServerError, + ) + return err +} diff --git a/http/json/decoder.go b/http/json/decoder.go new file mode 100644 index 0000000..c518f20 --- /dev/null +++ b/http/json/decoder.go @@ -0,0 +1,54 @@ +package json + +import ( + "encoding/json" + goflagsmode "github.com/ralvarezdev/go-flags/mode" + "net/http" +) + +type ( + // Decoder is the JSON decoder interface + Decoder interface { + Decode( + w http.ResponseWriter, + r *http.Request, + data interface{}, + ) (err error) + } + + // DefaultDecoder is the JSON decoder struct + DefaultDecoder struct { + mode *goflagsmode.Flag + } +) + +// NewDefaultDecoder creates a new JSON decoder +func NewDefaultDecoder(mode *goflagsmode.Flag) *DefaultDecoder { + return &DefaultDecoder{ + mode: mode, + } +} + +// Decode decodes the JSON data +func (d *DefaultDecoder) Decode( + w http.ResponseWriter, + r *http.Request, + data interface{}, +) (err error) { + // Check the data type + if err = checkJSONData(w, data, d.mode); err != nil { + return err + } + + // Decode JSON data + err = json.NewDecoder(r.Body).Decode(data) + if err != nil { + http.Error( + w, + err.Error(), + http.StatusBadRequest, + ) + return err + } + return nil +} diff --git a/http/json/encoder.go b/http/json/encoder.go new file mode 100644 index 0000000..c05fbd3 --- /dev/null +++ b/http/json/encoder.go @@ -0,0 +1,45 @@ +package json + +import ( + "encoding/json" + goflagsmode "github.com/ralvarezdev/go-flags/mode" + "net/http" +) + +type ( + // Encoder is an interface for encoding JSON data + Encoder interface { + Encode(w http.ResponseWriter, data interface{}) (err error) + } + + // DefaultEncoder is the JSON encoder struct + DefaultEncoder struct { + mode *goflagsmode.Flag + } +) + +// NewDefaultEncoder creates a new JSON encoder +func NewDefaultEncoder(mode *goflagsmode.Flag) *DefaultEncoder { + return &DefaultEncoder{ + mode: mode, + } +} + +// Encode encodes the data into JSON +func (d *DefaultEncoder) Encode( + w http.ResponseWriter, + data interface{}, +) (err error) { + // Check the data type + if err = checkJSONData(w, data, d.mode); err != nil { + return err + } + + // Encode JSON data + w.Header().Set("Content-Type", "application/json") + if err = json.NewEncoder(w).Encode(data); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return err + } + return nil +} diff --git a/http/json/errors.go b/http/json/errors.go new file mode 100644 index 0000000..0649272 --- /dev/null +++ b/http/json/errors.go @@ -0,0 +1,10 @@ +package json + +import ( + "errors" +) + +var ( + ErrNilJSONData = errors.New("json data is nil") + ErrJSONDataMustBeAPointer = errors.New("json data must be a pointer") +)