Skip to content

Commit

Permalink
MF-1368 - Add internal http api package for query params reading (#1384)
Browse files Browse the repository at this point in the history
* MF-1368 - Add internal http api package for query params reading

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix comments

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix comments

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix reviews

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Use internal/http and internalhttp alias

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Mv errors types to pkg

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Use httputil/query.go and remove aliases

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Add blank lines after error definitions

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Add ReadBoolValueQuery

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Mv readBoolValueQuery

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* User ErrNotFoundParam instead of pointer

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Revert ReadUintQuery to use default values

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Use default values for all query readers

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>
  • Loading branch information
manuio authored Mar 23, 2021
1 parent bcdc6d2 commit 9245e25
Show file tree
Hide file tree
Showing 33 changed files with 712 additions and 1,001 deletions.
105 changes: 18 additions & 87 deletions auth/api/http/groups/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import (
"encoding/json"
"io"
"net/http"
"strconv"
"strings"

kitot "github.com/go-kit/kit/tracing/opentracing"
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/auth"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/opentracing/opentracing-go"
)
Expand All @@ -23,20 +23,20 @@ var (
)

const (
contentType = "application/json"
maxNameSize = 254
offsetKey = "offset"
limitKey = "limit"
levelKey = "level"
metadataKey = "metadata"
treeKey = "tree"
groupType = "type"
contentType = "application/json"

defOffset = 0
defLimit = 10
defLevel = 1
defOffset = 0
defLimit = 10
defLevel = 1
)

// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc auth.Service, mux *bone.Mux, tracer opentracing.Tracer) *bone.Mux {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
Expand Down Expand Up @@ -127,17 +127,17 @@ func decodeListGroupsRequest(_ context.Context, r *http.Request) (interface{}, e
return nil, auth.ErrUnsupportedContentType
}

l, err := readUintQuery(r, levelKey, defLevel)
l, err := httputil.ReadUintQuery(r, levelKey, defLevel)
if err != nil {
return nil, err
}

m, err := readMetadataQuery(r, metadataKey)
m, err := httputil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}

t, err := readBoolQuery(r, treeKey)
t, err := httputil.ReadBoolQuery(r, treeKey, false)
if err != nil {
return nil, err
}
Expand All @@ -157,27 +157,27 @@ func decodeListMembersRequest(_ context.Context, r *http.Request) (interface{},
return nil, auth.ErrUnsupportedContentType
}

o, err := readUintQuery(r, offsetKey, defOffset)
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}

l, err := readUintQuery(r, limitKey, defLimit)
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}

m, err := readMetadataQuery(r, metadataKey)
m, err := httputil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}

tree, err := readBoolQuery(r, treeKey)
tree, err := httputil.ReadBoolQuery(r, treeKey, false)
if err != nil {
return nil, err
}

t, err := readStringQuery(r, groupType)
t, err := httputil.ReadStringQuery(r, groupType, "")
if err != nil {
return nil, err
}
Expand All @@ -199,22 +199,22 @@ func decodeListMembershipsRequest(_ context.Context, r *http.Request) (interface
return nil, auth.ErrUnsupportedContentType
}

o, err := readUintQuery(r, offsetKey, defOffset)
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}

l, err := readUintQuery(r, limitKey, defLimit)
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}

m, err := readMetadataQuery(r, metadataKey)
m, err := httputil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}

tree, err := readBoolQuery(r, treeKey)
tree, err := httputil.ReadBoolQuery(r, treeKey, false)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -282,75 +282,6 @@ func decodeAssignRequest(_ context.Context, r *http.Request) (interface{}, error
return req, nil
}

func readUintQuery(r *http.Request, key string, def uint64) (uint64, error) {
vals := bone.GetQuery(r, key)
if len(vals) > 1 {
return 0, errInvalidQueryParams
}

if len(vals) == 0 {
return def, nil
}

strval := vals[0]
val, err := strconv.ParseUint(strval, 10, 64)
if err != nil {
return 0, errInvalidQueryParams
}

return val, nil
}

func readMetadataQuery(r *http.Request, key string) (map[string]interface{}, error) {
vals := bone.GetQuery(r, key)
if len(vals) > 1 {
return nil, errInvalidQueryParams
}

if len(vals) == 0 {
return nil, nil
}

m := make(map[string]interface{})
err := json.Unmarshal([]byte(vals[0]), &m)
if err != nil {
return nil, errors.Wrap(errInvalidQueryParams, err)
}

return m, nil
}

func readBoolQuery(r *http.Request, key string) (bool, error) {
vals := bone.GetQuery(r, key)
if len(vals) > 1 {
return true, errInvalidQueryParams
}

if len(vals) == 0 {
return false, nil
}

b, err := strconv.ParseBool(vals[0])
if err != nil {
return false, errInvalidQueryParams
}

return b, nil
}

func readStringQuery(r *http.Request, key string) (string, error) {
vals := bone.GetQuery(r, key)
if len(vals) > 1 {
return "", errInvalidQueryParams
}

if len(vals) == 0 {
return "", nil
}

return vals[0], nil
}

func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
w.Header().Set("Content-Type", contentType)

Expand Down
2 changes: 1 addition & 1 deletion bootstrap/api/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -892,7 +892,7 @@ func TestList(t *testing.T) {
res: configPage{},
},
{
desc: "view list with invalid query params",
desc: "view list with invalid query parameters",
auth: validToken,
url: fmt.Sprintf("%s?offset=%d&limit=%d&state=%d&key=%%", path, 10, 10, bootstrap.Inactive),
status: http.StatusBadRequest,
Expand Down
29 changes: 14 additions & 15 deletions bootstrap/api/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ const (
)

var (
errUnsupportedContentType = errors.New("unsupported content type")
errInvalidQueryParams = errors.New("invalid query params")
errInvalidLimitParam = errors.New("invalid limit query param")
errInvalidOffsetParam = errors.New("invalid offset query param")
fullMatch = []string{"state", "external_id", "mainflux_id", "mainflux_key"}
partialMatch = []string{"name"}
errInvalidLimitParam = errors.New("invalid limit query param")
errInvalidOffsetParam = errors.New("invalid offset query param")
fullMatch = []string{"state", "external_id", "mainflux_id", "mainflux_key"}
partialMatch = []string{"name"}
)

// MakeHandler returns a HTTP handler for API endpoints.
Expand Down Expand Up @@ -110,7 +108,7 @@ func MakeHandler(svc bootstrap.Service, reader bootstrap.ConfigReader) http.Hand

func decodeAddRequest(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, errUnsupportedContentType
return nil, errors.ErrUnsupportedContentType
}

req := addReq{token: r.Header.Get("Authorization")}
Expand All @@ -123,7 +121,7 @@ func decodeAddRequest(_ context.Context, r *http.Request) (interface{}, error) {

func decodeUpdateRequest(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, errUnsupportedContentType
return nil, errors.ErrUnsupportedContentType
}

req := updateReq{key: r.Header.Get("Authorization")}
Expand All @@ -137,7 +135,7 @@ func decodeUpdateRequest(_ context.Context, r *http.Request) (interface{}, error

func decodeUpdateCertRequest(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, errUnsupportedContentType
return nil, errors.ErrUnsupportedContentType
}

req := updateCertReq{
Expand All @@ -154,7 +152,7 @@ func decodeUpdateCertRequest(_ context.Context, r *http.Request) (interface{}, e

func decodeUpdateConnRequest(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, errUnsupportedContentType
return nil, errors.ErrUnsupportedContentType
}

req := updateConnReq{key: r.Header.Get("Authorization")}
Expand All @@ -169,7 +167,7 @@ func decodeUpdateConnRequest(_ context.Context, r *http.Request) (interface{}, e
func decodeListRequest(_ context.Context, r *http.Request) (interface{}, error) {
q, err := url.ParseQuery(r.URL.RawQuery)
if err != nil {
return nil, errInvalidQueryParams
return nil, errors.ErrInvalidQueryParams
}

offset, limit, err := parsePagePrams(q)
Expand Down Expand Up @@ -200,7 +198,7 @@ func decodeBootstrapRequest(_ context.Context, r *http.Request) (interface{}, er

func decodeStateRequest(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, errUnsupportedContentType
return nil, errors.ErrUnsupportedContentType
}

req := changeStateReq{key: r.Header.Get("Authorization")}
Expand Down Expand Up @@ -254,10 +252,11 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
case errors.Error:
w.Header().Set("Content-Type", contentType)
switch {
case errors.Contains(errorVal, errUnsupportedContentType):
case errors.Contains(errorVal, errors.ErrUnsupportedContentType):
w.WriteHeader(http.StatusUnsupportedMediaType)
case errors.Contains(errorVal, errInvalidQueryParams):
case errors.Contains(errorVal, errors.ErrInvalidQueryParams):
w.WriteHeader(http.StatusBadRequest)

case errors.Contains(errorVal, bootstrap.ErrMalformedEntity):
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(errorVal, bootstrap.ErrNotFound):
Expand Down Expand Up @@ -292,7 +291,7 @@ func parseUint(s string) (uint64, error) {

ret, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return 0, errInvalidQueryParams
return 0, errors.ErrInvalidQueryParams
}

return ret, nil
Expand Down
Loading

0 comments on commit 9245e25

Please sign in to comment.