mirror of
https://github.com/absmach/supermq.git
synced 2026-06-23 07:00:25 +00:00
NOISSUE - Add property based testing to bootstrap API (#2095)
Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com>
This commit is contained in:
@@ -32,6 +32,7 @@ env:
|
||||
THINGS_URL: http://localhost:9000
|
||||
INVITATIONS_URL: http://localhost:9020
|
||||
AUTH_URL: http://localhost:8189
|
||||
BOOTSTRAP_URL: http://localhost:9013
|
||||
|
||||
jobs:
|
||||
api-test:
|
||||
@@ -50,7 +51,7 @@ jobs:
|
||||
run: make all -j $(nproc) && make dockers_dev -j $(nproc)
|
||||
|
||||
- name: Start containers
|
||||
run: make run up args="-d" && sleep 10
|
||||
run: make run up args="-d" && make run_addons up args="-d"
|
||||
|
||||
- name: Set access token
|
||||
run: |
|
||||
@@ -159,6 +160,16 @@ jobs:
|
||||
report: false
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --contrib-openapi-formats-uuid --hypothesis-suppress-health-check=filter_too_much --stateful=links'
|
||||
|
||||
- name: Run Bootstrap API tests
|
||||
if: steps.changes.outputs.bootstrap == 'true'
|
||||
uses: schemathesis/action@v1
|
||||
with:
|
||||
schema: api/openapi/bootstrap.yml
|
||||
base-url: ${{ env.BOOTSTRAP_URL }}
|
||||
checks: all
|
||||
report: false
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --contrib-openapi-formats-uuid --hypothesis-suppress-health-check=filter_too_much --stateful=links'
|
||||
|
||||
- name: Stop containers
|
||||
if: always()
|
||||
run: make run down args="-v"
|
||||
|
||||
@@ -154,6 +154,7 @@ test_api_users: TEST_API_URL := http://localhost:9002
|
||||
test_api_things: TEST_API_URL := http://localhost:9000
|
||||
test_api_invitations: TEST_API_URL := http://localhost:9020
|
||||
test_api_auth: TEST_API_URL := http://localhost:8189
|
||||
test_api_bootstrap: TEST_API_URL := http://localhost:9013
|
||||
|
||||
$(TEST_API):
|
||||
$(call test_api_service,$(@),$(TEST_API_URL))
|
||||
|
||||
+134
-64
@@ -25,10 +25,11 @@ tags:
|
||||
externalDocs:
|
||||
description: Find out more about Configs
|
||||
url: https://docs.magistrala.abstractmachines.fr/
|
||||
|
||||
|
||||
paths:
|
||||
/things/configs:
|
||||
post:
|
||||
operationId: createConfig
|
||||
summary: Adds new config
|
||||
description: |
|
||||
Adds new config to the list of config owned by user identified using
|
||||
@@ -38,17 +39,28 @@ paths:
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ConfigCreateReq"
|
||||
responses:
|
||||
'201':
|
||||
"201":
|
||||
$ref: "#/components/responses/ConfigCreateRes"
|
||||
'400':
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'415':
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"409":
|
||||
description: Failed due to using an existing identity.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
"503":
|
||||
description: Failed to receive response from the things service.
|
||||
get:
|
||||
operationId: getConfigs
|
||||
summary: Retrieves managed configs
|
||||
description: |
|
||||
Retrieves a list of managed configs. Due to performance concerns, data
|
||||
@@ -63,31 +75,37 @@ paths:
|
||||
- $ref: "#/components/parameters/State"
|
||||
- $ref: "#/components/parameters/Name"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
$ref: "#/components/responses/ConfigListRes"
|
||||
'400':
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
'401':
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/configs/{configId}:
|
||||
get:
|
||||
operationId: getConfig
|
||||
summary: Retrieves config info (with channels).
|
||||
tags:
|
||||
- configs
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConfigId"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
$ref: "#/components/responses/ConfigRes"
|
||||
'401':
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
"404":
|
||||
description: Config does not exist.
|
||||
'500':
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
put:
|
||||
operationId: updateConfig
|
||||
summary: Updates config info
|
||||
description: |
|
||||
Update is performed by replacing the current resource data with values
|
||||
@@ -98,21 +116,24 @@ paths:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConfigId"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ConfigUpdateReq"
|
||||
$ref: "#/components/requestBodies/ConfigUpdateReq"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Config updated.
|
||||
'400':
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
"404":
|
||||
description: Config does not exist.
|
||||
'415':
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
delete:
|
||||
operationId: removeConfig
|
||||
summary: Removes a Config
|
||||
description: |
|
||||
Removes a Config. In case of successful removal the service will ensure
|
||||
@@ -122,16 +143,19 @@ paths:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConfigId"
|
||||
responses:
|
||||
'204':
|
||||
"204":
|
||||
description: Config removed.
|
||||
'400':
|
||||
"400":
|
||||
description: Failed due to malformed config ID.
|
||||
'401':
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/configs/certs/{configId}:
|
||||
patch:
|
||||
operationId: updateConfigCerts
|
||||
summary: Updates certs
|
||||
description: |
|
||||
Update is performed by replacing the current certificate data with values
|
||||
@@ -143,21 +167,24 @@ paths:
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ConfigCertUpdateReq"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Config updated.
|
||||
$ref: "#/components/responses/ConfigUpdateCertsRes"
|
||||
'400':
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
"404":
|
||||
description: Config does not exist.
|
||||
'415':
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/configs/connections/{configId}:
|
||||
put:
|
||||
operationId: updateConfigConnections
|
||||
summary: Updates channels the thing is connected to
|
||||
description: |
|
||||
Update connections performs update of the channel list corresponding
|
||||
@@ -169,20 +196,23 @@ paths:
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/ConfigConnUpdateReq"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Config updated.
|
||||
'400':
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'404':
|
||||
"404":
|
||||
description: Config does not exist.
|
||||
'415':
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
'500':
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/bootstrap/{externalId}:
|
||||
get:
|
||||
operationId: getBootstrapConfig
|
||||
summary: Retrieves configuration.
|
||||
description: |
|
||||
Retrieves a configuration with given external ID and external key.
|
||||
@@ -193,18 +223,21 @@ paths:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ExternalId"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
$ref: "#/components/responses/BootstrapConfigRes"
|
||||
'400':
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
'401':
|
||||
"401":
|
||||
description: Missing or invalid external key provided.
|
||||
'404':
|
||||
"404":
|
||||
description: Failed to retrieve corresponding config.
|
||||
'500':
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/bootstrap/secure/{externalId}:
|
||||
get:
|
||||
operationId: getSecureBootstrapConfig
|
||||
summary: Retrieves configuration.
|
||||
description: |
|
||||
Retrieves a configuration with given external ID and encrypted external key.
|
||||
@@ -215,15 +248,22 @@ paths:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ExternalId"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
$ref: "#/components/responses/BootstrapConfigRes"
|
||||
'404':
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: |
|
||||
Failed to retrieve corresponding config.
|
||||
'500':
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/things/state/{configId}:
|
||||
put:
|
||||
operationId: updateConfigState
|
||||
summary: Updates Config state.
|
||||
description: |
|
||||
Updating state represents enabling/disabling Config, i.e. connecting
|
||||
@@ -233,15 +273,21 @@ paths:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ConfigId"
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/ConfigStateUpdateReq'
|
||||
$ref: "#/components/requestBodies/ConfigStateUpdateReq"
|
||||
responses:
|
||||
'204':
|
||||
"204":
|
||||
description: Config removed.
|
||||
'400':
|
||||
"400":
|
||||
description: Failed due to malformed config's ID.
|
||||
'401':
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
'500':
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
@@ -249,9 +295,9 @@ paths:
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
'500':
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
@@ -453,12 +499,14 @@ components:
|
||||
description: External key.
|
||||
thing_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: ID of the corresponding Magistrala Thing.
|
||||
channels:
|
||||
type: array
|
||||
minItems: 0
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
content:
|
||||
type: string
|
||||
name:
|
||||
@@ -468,7 +516,7 @@ components:
|
||||
description: Thing Certificate.
|
||||
client_key:
|
||||
type: string
|
||||
description: Thing Private Key.
|
||||
description: Thing Private Key.
|
||||
ca_cert:
|
||||
type: string
|
||||
required:
|
||||
@@ -513,6 +561,7 @@ components:
|
||||
minItems: 0
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
ConfigStateUpdateReq:
|
||||
description: Update the state of the Config.
|
||||
content:
|
||||
@@ -525,14 +574,14 @@ components:
|
||||
|
||||
responses:
|
||||
ConfigCreateRes:
|
||||
description: Config registered.
|
||||
headers:
|
||||
Location:
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
description: Created configuration's relative URL (i.e. /things/configs/{configId}).
|
||||
description: Config registered.
|
||||
headers:
|
||||
Location:
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
description: Created configuration's relative URL (i.e. /things/configs/{configId}).
|
||||
ConfigListRes:
|
||||
description: Data retrieved. Configs from this list don't contain channels.
|
||||
content:
|
||||
@@ -545,10 +594,31 @@ components:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Config"
|
||||
links:
|
||||
update:
|
||||
operationId: updateConfig
|
||||
parameters:
|
||||
configId: $response.body#/id
|
||||
updateCerts:
|
||||
operationId: updateConfigCerts
|
||||
parameters:
|
||||
configId: $response.body#/id
|
||||
updateConnections:
|
||||
operationId: updateConfigConnections
|
||||
parameters:
|
||||
configId: $response.body#/id
|
||||
updateState:
|
||||
operationId: updateConfigState
|
||||
parameters:
|
||||
configId: $response.body#/id
|
||||
delete:
|
||||
operationId: removeConfig
|
||||
parameters:
|
||||
configId: $response.body#/id
|
||||
BootstrapConfigRes:
|
||||
description: |
|
||||
Data retrieved. If secure, a response is encrypted using
|
||||
the secret key, so the response is in the binary form.
|
||||
Data retrieved. If secure, a response is encrypted using
|
||||
the secret key, so the response is in the binary form.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -558,7 +628,7 @@ components:
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/json:
|
||||
application/health+json:
|
||||
schema:
|
||||
$ref: "./schemas/HealthInfo.yml"
|
||||
ConfigUpdateCertsRes:
|
||||
|
||||
@@ -1162,7 +1162,7 @@ func TestBootstrap(t *testing.T) {
|
||||
desc: "bootstrap a Thing with an empty key",
|
||||
externalID: c.ExternalID,
|
||||
externalKey: "",
|
||||
status: http.StatusUnauthorized,
|
||||
status: http.StatusBadRequest,
|
||||
res: missingKeyRes,
|
||||
secure: false,
|
||||
err: errors.Wrap(bootstrap.ErrBootstrap, svcerr.ErrAuthentication),
|
||||
|
||||
+12
-80
@@ -13,9 +13,9 @@ import (
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/bootstrap"
|
||||
"github.com/absmach/magistrala/internal/api"
|
||||
"github.com/absmach/magistrala/internal/apiutil"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"github.com/go-chi/chi/v5"
|
||||
kithttp "github.com/go-kit/kit/transport/http"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
@@ -41,7 +41,7 @@ var (
|
||||
// MakeHandler returns a HTTP handler for API endpoints.
|
||||
func MakeHandler(svc bootstrap.Service, reader bootstrap.ConfigReader, logger *slog.Logger, instanceID string) http.Handler {
|
||||
opts := []kithttp.ServerOption{
|
||||
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
|
||||
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, api.EncodeError)),
|
||||
}
|
||||
|
||||
r := chi.NewRouter()
|
||||
@@ -51,43 +51,43 @@ func MakeHandler(svc bootstrap.Service, reader bootstrap.ConfigReader, logger *s
|
||||
r.Post("/", otelhttp.NewHandler(kithttp.NewServer(
|
||||
addEndpoint(svc),
|
||||
decodeAddRequest,
|
||||
encodeResponse,
|
||||
api.EncodeResponse,
|
||||
opts...), "add").ServeHTTP)
|
||||
|
||||
r.Get("/", otelhttp.NewHandler(kithttp.NewServer(
|
||||
listEndpoint(svc),
|
||||
decodeListRequest,
|
||||
encodeResponse,
|
||||
api.EncodeResponse,
|
||||
opts...), "list").ServeHTTP)
|
||||
|
||||
r.Get("/{configID}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
viewEndpoint(svc),
|
||||
decodeEntityRequest,
|
||||
encodeResponse,
|
||||
api.EncodeResponse,
|
||||
opts...), "view").ServeHTTP)
|
||||
|
||||
r.Put("/{configID}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
updateEndpoint(svc),
|
||||
decodeUpdateRequest,
|
||||
encodeResponse,
|
||||
api.EncodeResponse,
|
||||
opts...), "update").ServeHTTP)
|
||||
|
||||
r.Delete("/{configID}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
removeEndpoint(svc),
|
||||
decodeEntityRequest,
|
||||
encodeResponse,
|
||||
api.EncodeResponse,
|
||||
opts...), "remove").ServeHTTP)
|
||||
|
||||
r.Patch("/certs/{certID}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
updateCertEndpoint(svc),
|
||||
decodeUpdateCertRequest,
|
||||
encodeResponse,
|
||||
api.EncodeResponse,
|
||||
opts...), "update_cert").ServeHTTP)
|
||||
|
||||
r.Put("/connections/{connID}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
updateConnEndpoint(svc),
|
||||
decodeUpdateConnRequest,
|
||||
encodeResponse,
|
||||
api.EncodeResponse,
|
||||
opts...), "update_connections").ServeHTTP)
|
||||
})
|
||||
|
||||
@@ -95,12 +95,12 @@ func MakeHandler(svc bootstrap.Service, reader bootstrap.ConfigReader, logger *s
|
||||
r.Get("/", otelhttp.NewHandler(kithttp.NewServer(
|
||||
bootstrapEndpoint(svc, reader, false),
|
||||
decodeBootstrapRequest,
|
||||
encodeResponse,
|
||||
api.EncodeResponse,
|
||||
opts...), "bootstrap").ServeHTTP)
|
||||
r.Get("/{externalID}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
bootstrapEndpoint(svc, reader, false),
|
||||
decodeBootstrapRequest,
|
||||
encodeResponse,
|
||||
api.EncodeResponse,
|
||||
opts...), "bootstrap").ServeHTTP)
|
||||
r.Get("/secure/{externalID}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
bootstrapEndpoint(svc, reader, true),
|
||||
@@ -112,7 +112,7 @@ func MakeHandler(svc bootstrap.Service, reader bootstrap.ConfigReader, logger *s
|
||||
r.Put("/state/{thingID}", otelhttp.NewHandler(kithttp.NewServer(
|
||||
stateEndpoint(svc),
|
||||
decodeStateRequest,
|
||||
encodeResponse,
|
||||
api.EncodeResponse,
|
||||
opts...), "update_state").ServeHTTP)
|
||||
})
|
||||
r.Get("/health", magistrala.Health("bootstrap", instanceID))
|
||||
@@ -242,23 +242,6 @@ func decodeEntityRequest(_ context.Context, r *http.Request) (interface{}, error
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
if ar, ok := response.(magistrala.Response); ok {
|
||||
for k, v := range ar.Headers() {
|
||||
w.Header().Set(k, v)
|
||||
}
|
||||
|
||||
w.WriteHeader(ar.Code())
|
||||
|
||||
if ar.Empty() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
func encodeSecureRes(_ context.Context, w http.ResponseWriter, response interface{}) error {
|
||||
w.Header().Set("Content-Type", byteContentType)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
@@ -270,57 +253,6 @@ func encodeSecureRes(_ context.Context, w http.ResponseWriter, response interfac
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
var wrapper error
|
||||
if errors.Contains(err, apiutil.ErrValidation) {
|
||||
wrapper, err = errors.Unwrap(err)
|
||||
}
|
||||
|
||||
switch {
|
||||
case errors.Contains(err, svcerr.ErrAuthentication),
|
||||
errors.Contains(err, apiutil.ErrBearerToken),
|
||||
errors.Contains(err, apiutil.ErrBearerKey):
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
case errors.Contains(err, apiutil.ErrUnsupportedContentType):
|
||||
w.WriteHeader(http.StatusUnsupportedMediaType)
|
||||
case errors.Contains(err, apiutil.ErrInvalidQueryParams),
|
||||
errors.Contains(err, svcerr.ErrMalformedEntity),
|
||||
errors.Contains(err, apiutil.ErrMissingID),
|
||||
errors.Contains(err, apiutil.ErrBootstrapState),
|
||||
errors.Contains(err, apiutil.ErrLimitSize):
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
case errors.Contains(err, svcerr.ErrNotFound):
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
case errors.Contains(err, bootstrap.ErrExternalKey),
|
||||
errors.Contains(err, bootstrap.ErrExternalKeySecure),
|
||||
errors.Contains(err, svcerr.ErrAuthorization):
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
case errors.Contains(err, bootstrap.ErrThings):
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
case errors.Contains(err, svcerr.ErrConflict):
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
case errors.Contains(err, svcerr.ErrCreateEntity),
|
||||
errors.Contains(err, svcerr.ErrUpdateEntity),
|
||||
errors.Contains(err, svcerr.ErrViewEntity),
|
||||
errors.Contains(err, svcerr.ErrRemoveEntity):
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
default:
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
if wrapper != nil {
|
||||
err = errors.Wrap(wrapper, err)
|
||||
}
|
||||
|
||||
if errorVal, ok := err.(errors.Error); ok {
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
if err := json.NewEncoder(w).Encode(errorVal); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseFilter(values url.Values) bootstrap.Filter {
|
||||
ret := bootstrap.Filter{
|
||||
FullMatch: make(map[string]string),
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/bootstrap"
|
||||
"github.com/absmach/magistrala/internal/apiutil"
|
||||
mgclients "github.com/absmach/magistrala/pkg/clients"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
@@ -129,10 +130,11 @@ func EncodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
errors.Contains(err, apiutil.ErrMissingRelation),
|
||||
errors.Contains(err, apiutil.ErrPasswordFormat),
|
||||
errors.Contains(err, apiutil.ErrInvalidLevel),
|
||||
errors.Contains(err, apiutil.ErrInvalidQueryParams),
|
||||
errors.Contains(err, apiutil.ErrMalformedPolicy),
|
||||
errors.Contains(err, apiutil.ErrInvalidAPIKey),
|
||||
errors.Contains(err, apiutil.ErrMissingName):
|
||||
errors.Contains(err, apiutil.ErrMissingName),
|
||||
errors.Contains(err, apiutil.ErrBootstrapState),
|
||||
errors.Contains(err, apiutil.ErrInvalidQueryParams):
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
case errors.Contains(err, svcerr.ErrAuthentication),
|
||||
errors.Contains(err, svcerr.ErrLogin),
|
||||
@@ -144,7 +146,9 @@ func EncodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
errors.Contains(err, errors.ErrStatusAlreadyAssigned):
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
case errors.Contains(err, svcerr.ErrAuthorization),
|
||||
errors.Contains(err, svcerr.ErrDomainAuthorization):
|
||||
errors.Contains(err, svcerr.ErrDomainAuthorization),
|
||||
errors.Contains(err, bootstrap.ErrExternalKey),
|
||||
errors.Contains(err, bootstrap.ErrExternalKeySecure):
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
case errors.Contains(err, apiutil.ErrUnsupportedContentType):
|
||||
w.WriteHeader(http.StatusUnsupportedMediaType)
|
||||
@@ -156,6 +160,8 @@ func EncodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
errors.Contains(err, svcerr.ErrDeletePolicies),
|
||||
errors.Contains(err, svcerr.ErrRemoveEntity):
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
case errors.Contains(err, bootstrap.ErrThings):
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
default:
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user