Skip to content

Commit

Permalink
refactor: added RequestError interface and its implementations
Browse files Browse the repository at this point in the history
* Added RequestError interface and its implementations (FieldError, HeaderError and ParameterError)
* Re-structured folders
  • Loading branch information
ralvarezdev committed Jan 13, 2025
1 parent aec6c19 commit 3ffe037
Show file tree
Hide file tree
Showing 18 changed files with 146 additions and 70 deletions.
3 changes: 2 additions & 1 deletion http/client_ip.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package http

import (
"github.com/ralvarezdev/go-net/http/status"
"net/http"
"strings"
)

// GetClientIP returns the client's IP address from the request
func GetClientIP(r *http.Request) string {
// Check if the request has a forwarded IP from a proxy or load balancer
forwarded := r.Header.Get(XForwardedFor)
forwarded := r.Header.Get(status.XForwardedFor)
if forwarded != "" {
// X-Forwarded-For can contain multiple IP addresses, the client's IP is the first one
ip := strings.Split(forwarded, ",")[0]
Expand Down
8 changes: 6 additions & 2 deletions http/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ package http

import (
"errors"
gojwtnethttp "github.com/ralvarezdev/go-jwt/net/http"
gonethttpresponse "github.com/ralvarezdev/go-net/http/response"
)

var (
ErrInvalidRequestBody = "invalid request body: %v"
ErrNilRequestBody = errors.New("request body cannot be nil")
ErrInDevelopment = errors.New("in development")
ErrInvalidAuthorizationHeader = errors.New("invalid authorization header")
ErrInvalidAuthorizationHeader = gonethttpresponse.NewHeaderError(
gojwtnethttp.AuthorizationHeaderKey,
"invalid authorization header",
)
)
2 changes: 1 addition & 1 deletion http/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package handler

import (
goflagsmode "github.com/ralvarezdev/go-flags/mode"
gonethttperrors "github.com/ralvarezdev/go-net/http/errors"
gonethttpjson "github.com/ralvarezdev/go-net/http/json"
gonethttpresponse "github.com/ralvarezdev/go-net/http/response"
gonethttperrors "github.com/ralvarezdev/go-net/http/status/errors"
"net/http"
)

Expand Down
14 changes: 8 additions & 6 deletions http/json/body.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ func bodyDecodeErrorHandler(
return encoder.Encode(
w,
gonethttpresponse.NewDebugFailResponse(
gonethttpresponse.NewFieldErrorsBodyData(
fieldName,
fmt.Errorf(
ErrFieldInvalidValue,
fieldTypeName,
fieldValue,
gonethttpresponse.NewRequestErrorsBodyData(
gonethttpresponse.NewFieldError(
fieldName,
fmt.Sprintf(
ErrFieldInvalidValue,
fieldTypeName,
fieldValue,
),
),
),
err,
Expand Down
4 changes: 2 additions & 2 deletions http/json/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package json
import (
"encoding/json"
goflagsmode "github.com/ralvarezdev/go-flags/mode"
gonethttperrors "github.com/ralvarezdev/go-net/http/errors"
gonethttpresponse "github.com/ralvarezdev/go-net/http/response"
gonethttpstatuserrors "github.com/ralvarezdev/go-net/http/status/errors"
"io"
"net/http"
)
Expand Down Expand Up @@ -52,7 +52,7 @@ func (d *DefaultDecoder) Decode(
if dest == nil {
_ = d.encoder.Encode(
w, gonethttpresponse.NewDebugErrorResponse(
gonethttperrors.InternalServerError,
gonethttpstatuserrors.InternalServerError,
err,
nil,
nil,
Expand Down
4 changes: 2 additions & 2 deletions http/json/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package json
import (
"encoding/json"
"github.com/ralvarezdev/go-flags/mode"
gonethttperrors "github.com/ralvarezdev/go-net/http/errors"
gonethttpresponse "github.com/ralvarezdev/go-net/http/response"
gonethttpstatuserrors "github.com/ralvarezdev/go-net/http/status/errors"
"net/http"
)

Expand Down Expand Up @@ -43,7 +43,7 @@ func (d *DefaultEncoder) Encode(
return d.Encode(
w,
gonethttpresponse.NewDebugErrorResponse(
gonethttperrors.InternalServerError,
gonethttpstatuserrors.InternalServerError,
err,
nil,
nil,
Expand Down
1 change: 0 additions & 1 deletion http/json/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
)

var (
ErrNilData = errors.New("json data is nil")
ErrNilEncoder = errors.New("json encoder is nil")
ErrNilDecoder = errors.New("json decoder is nil")
ErrUnmarshalBodyDataFailed = errors.New("failed to unmarshal json body data")
Expand Down
4 changes: 2 additions & 2 deletions http/json/stream_decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package json
import (
"encoding/json"
goflagsmode "github.com/ralvarezdev/go-flags/mode"
gonethttperrors "github.com/ralvarezdev/go-net/http/errors"
gonethttpresponse "github.com/ralvarezdev/go-net/http/response"
gonethttpstatuserrors "github.com/ralvarezdev/go-net/http/status/errors"
"net/http"
)

Expand Down Expand Up @@ -42,7 +42,7 @@ func (d *DefaultStreamDecoder) Decode(
if dest == nil {
_ = d.encoder.Encode(
w, gonethttpresponse.NewDebugErrorResponse(
gonethttperrors.InternalServerError,
gonethttpstatuserrors.InternalServerError,
err,
nil,
nil,
Expand Down
4 changes: 2 additions & 2 deletions http/json/stream_encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package json
import (
"encoding/json"
goflagsmode "github.com/ralvarezdev/go-flags/mode"
gonethttperrors "github.com/ralvarezdev/go-net/http/errors"
gonethttpresponse "github.com/ralvarezdev/go-net/http/response"
gonethttpstatuserrors "github.com/ralvarezdev/go-net/http/status/errors"
"net/http"
)

Expand Down Expand Up @@ -36,7 +36,7 @@ func (d *DefaultStreamEncoder) Encode(
_ = d.Encode(
w,
gonethttpresponse.NewDebugErrorResponse(
gonethttperrors.InternalServerError,
gonethttpstatuserrors.InternalServerError,
err,
nil,
nil,
Expand Down
19 changes: 14 additions & 5 deletions http/jwt/validator/handler.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package validator

import (
gojwtnethttp "github.com/ralvarezdev/go-jwt/net/http"
gonethttpjson "github.com/ralvarezdev/go-net/http/json"
gonethttpresponse "github.com/ralvarezdev/go-net/http/response"
"net/http"
)

// FailHandler handles the possible JWT validation errors
type FailHandler func(w http.ResponseWriter, err ...error)
type FailHandler func(
w http.ResponseWriter,
error error,
)

// NewDefaultFailHandler function
func NewDefaultFailHandler(
Expand All @@ -18,13 +22,18 @@ func NewDefaultFailHandler(
return nil, gonethttpjson.ErrNilEncoder
}

return func(w http.ResponseWriter, err ...error) {
return func(
w http.ResponseWriter,
error error,
) {
// Encode the response
_ = jsonEncoder.Encode(
w, gonethttpresponse.NewFailResponse(
gonethttpresponse.NewFieldErrorsBodyData(
"authorization",
err...,
gonethttpresponse.NewRequestErrorsBodyData(
gonethttpresponse.NewHeaderError(
gojwtnethttp.AuthorizationHeaderKey,
error.Error(),
),
),
nil,
http.StatusUnauthorized,
Expand Down
15 changes: 0 additions & 15 deletions http/response/common.go

This file was deleted.

5 changes: 0 additions & 5 deletions http/response/constants.go

This file was deleted.

3 changes: 1 addition & 2 deletions http/response/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ import (
)

var (
ErrNilResponse = errors.New("response cannot be nil")
ErrNilResponseHTTPStatus = errors.New("response http status cannot be nil")
ErrNilResponse = errors.New("response cannot be nil")
)
102 changes: 84 additions & 18 deletions http/response/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,29 @@ type (
Code *int `json:"code,omitempty"`
}

// RequestError struct
RequestError interface {
Key() string
Error() string
}

// FieldError struct
FieldError struct {
Field string
Err string
}

// HeaderError struct
HeaderError struct {
Header string
Err string
}

// ParameterError struct
ParameterError struct {
Parameter string
Err string
}
)

// NewJSendSuccessBody creates a new success response body
Expand Down Expand Up @@ -169,37 +187,85 @@ func NewFieldError(
}
}

// Key returns the field name
func (f *FieldError) Key() string {
return f.Field
}

// Error returns the field error as a string
func (f *FieldError) Error() string {
return f.Err
}

// NewFieldErrorsBodyData creates a new field errors body data
func NewFieldErrorsBodyData(
fieldErrors ...FieldError,
// NewHeaderError creates a new header error
func NewHeaderError(
header, err string,
) *HeaderError {
return &HeaderError{
Header: header,
Err: err,
}
}

// Key returns the header name
func (h *HeaderError) Key() string {
return h.Header
}

// Error returns the header error as a string
func (h *HeaderError) Error() string {
return h.Err
}

// NewParameterError creates a new parameter error
func NewParameterError(
parameter, err string,
) *ParameterError {
return &ParameterError{
Parameter: parameter,
Err: err,
}
}

// Key returns the parameter name
func (p *ParameterError) Key() string {
return p.Parameter
}

// Error returns the parameter error as a string
func (p *ParameterError) Error() string {
return p.Err

}

// NewRequestErrorsBodyData creates a new request errors body data
func NewRequestErrorsBodyData(
requestErrors ...RequestError,
) *map[string]*[]string {
// Check if there are field errors
if len(fieldErrors) == 0 {
// Check if there are request errors
if len(requestErrors) == 0 {
return nil
}

// Initialize the field errors map
fieldErrorsMap := make(map[string]*[]string)
// Initialize the request errors map
requestErrorsMap := make(map[string]*[]string)

// Iterate over the request errors
for _, requestError := range requestErrors {
// Check if the request name exists in the map
requestKeyErrors, ok := requestErrorsMap[requestError.Key()]

// Iterate over the field errors
for _, fieldError := range fieldErrors {
// Check if the field name exists in the map
if _, ok := fieldErrorsMap[fieldError.Field]; !ok {
// Initialize the field errors slice
fieldErrorsMap[fieldError.Field] = &[]string{fieldError.Err}
if !ok {
// Initialize the request errors slice
requestErrorsMap[requestError.Key()] = &[]string{requestError.Error()}
} else {
// Append the error to the field errors slice
*fieldErrorsMap[fieldError.Field] = append(
*fieldErrorsMap[fieldError.Field],
fieldError.Err,
// Append the error to the request errors slice
*requestKeyErrors = append(
*requestKeyErrors,
requestError.Key(),
)
}
}

return &fieldErrorsMap
return &requestErrorsMap
}
2 changes: 1 addition & 1 deletion http/constants.go → http/status/constants.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package http
package status

import (
"net/http"
Expand Down
4 changes: 2 additions & 2 deletions http/errors/errors.go → http/status/errors/errors.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package http
package errors

import (
"errors"
gonethttp "github.com/ralvarezdev/go-net/http"
gonethttp "github.com/ralvarezdev/go-net/http/status"
)

var (
Expand Down
16 changes: 16 additions & 0 deletions http/status/response/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package response

import (
"github.com/ralvarezdev/go-net/http/response"
gonethttperrors "github.com/ralvarezdev/go-net/http/status/errors"
"net/http"
)

var (
InternalServerError = response.NewErrorResponse(
gonethttperrors.InternalServerError,
nil,
nil,
http.StatusInternalServerError,
)
)
Loading

0 comments on commit 3ffe037

Please sign in to comment.