mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 01:12:56 +03:00
Improve error messages of Metadata API.
### Description This PR improves error messages in our metadata API by displaying a message with the name of the failing command and a link to our documentation. Furthermore, it harmonizes our internal uses of `withObject`, to respect the convention of using the Haskell type name, now that the Aeson error message is displayed as an "internal error message". https://github.com/hasura/graphql-engine-mono/pull/1905 GitOrigin-RevId: e4064ba3290306437aa7e45faa316c60e51bc6b6
This commit is contained in:
parent
e77b79ae02
commit
21254256a1
@ -39,7 +39,7 @@ instance (Backend b) => ToJSON (AddComputedField b) where
|
|||||||
toJSON = genericToJSON hasuraJSON
|
toJSON = genericToJSON hasuraJSON
|
||||||
|
|
||||||
instance (Backend b) => FromJSON (AddComputedField b) where
|
instance (Backend b) => FromJSON (AddComputedField b) where
|
||||||
parseJSON = withObject "add computed field" $ \o ->
|
parseJSON = withObject "AddComputedField" $ \o ->
|
||||||
AddComputedField
|
AddComputedField
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
@ -78,7 +78,7 @@ data DropComputedField b
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance (Backend b) => FromJSON (DropComputedField b) where
|
instance (Backend b) => FromJSON (DropComputedField b) where
|
||||||
parseJSON = withObject "drop computed field" $ \o ->
|
parseJSON = withObject "DropComputedField" $ \o ->
|
||||||
DropComputedField
|
DropComputedField
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
|
@ -57,7 +57,7 @@ data CreateEventTriggerQuery (b :: BackendType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance Backend b => FromJSON (CreateEventTriggerQuery b) where
|
instance Backend b => FromJSON (CreateEventTriggerQuery b) where
|
||||||
parseJSON = withObject "create event trigger" \o -> do
|
parseJSON = withObject "CreateEventTriggerQuery" \o -> do
|
||||||
sourceName <- o .:? "source" .!= defaultSource
|
sourceName <- o .:? "source" .!= defaultSource
|
||||||
name <- o .: "name"
|
name <- o .: "name"
|
||||||
table <- o .: "table"
|
table <- o .: "table"
|
||||||
@ -102,7 +102,7 @@ data DeleteEventTriggerQuery (b :: BackendType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance FromJSON (DeleteEventTriggerQuery b) where
|
instance FromJSON (DeleteEventTriggerQuery b) where
|
||||||
parseJSON = withObject "delete event trigger" $ \o ->
|
parseJSON = withObject "DeleteEventTriggerQuery" $ \o ->
|
||||||
DeleteEventTriggerQuery
|
DeleteEventTriggerQuery
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "name"
|
<*> o .: "name"
|
||||||
@ -115,7 +115,7 @@ data RedeliverEventQuery (b :: BackendType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance FromJSON (RedeliverEventQuery b) where
|
instance FromJSON (RedeliverEventQuery b) where
|
||||||
parseJSON = withObject "redeliver event trigger" $ \o ->
|
parseJSON = withObject "RedeliverEventQuery" $ \o ->
|
||||||
RedeliverEventQuery
|
RedeliverEventQuery
|
||||||
<$> o .: "event_id"
|
<$> o .: "event_id"
|
||||||
<*> o .:? "source" .!= defaultSource
|
<*> o .:? "source" .!= defaultSource
|
||||||
@ -129,7 +129,7 @@ data InvokeEventTriggerQuery (b :: BackendType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance Backend b => FromJSON (InvokeEventTriggerQuery b) where
|
instance Backend b => FromJSON (InvokeEventTriggerQuery b) where
|
||||||
parseJSON = withObject "invoke event trigger" $ \o ->
|
parseJSON = withObject "InvokeEventTriggerQuery" $ \o ->
|
||||||
InvokeEventTriggerQuery
|
InvokeEventTriggerQuery
|
||||||
<$> o .: "name"
|
<$> o .: "name"
|
||||||
<*> o .:? "source" .!= defaultSource
|
<*> o .:? "source" .!= defaultSource
|
||||||
|
@ -124,7 +124,7 @@ data ReplaceMetadataV1
|
|||||||
deriving (Eq)
|
deriving (Eq)
|
||||||
|
|
||||||
instance FromJSON ReplaceMetadataV1 where
|
instance FromJSON ReplaceMetadataV1 where
|
||||||
parseJSON = withObject "Object" $ \o -> do
|
parseJSON = withObject "ReplaceMetadataV1" $ \o -> do
|
||||||
version <- o .:? "version" .!= MVVersion1
|
version <- o .:? "version" .!= MVVersion1
|
||||||
case version of
|
case version of
|
||||||
MVVersion3 -> RMWithSources <$> parseJSON (Object o)
|
MVVersion3 -> RMWithSources <$> parseJSON (Object o)
|
||||||
|
@ -375,7 +375,7 @@ data SetPermComment b
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance (Backend b) => FromJSON (SetPermComment b) where
|
instance (Backend b) => FromJSON (SetPermComment b) where
|
||||||
parseJSON = withObject "set permission comment" $ \o ->
|
parseJSON = withObject "SetPermComment" $ \o ->
|
||||||
SetPermComment
|
SetPermComment
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
|
@ -111,7 +111,7 @@ data DropPerm (a :: BackendType -> Type) b
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance (Backend b) => FromJSON (DropPerm a b) where
|
instance (Backend b) => FromJSON (DropPerm a b) where
|
||||||
parseJSON = withObject "drop permission" $ \o ->
|
parseJSON = withObject "DropPerm" $ \o ->
|
||||||
DropPerm
|
DropPerm
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
|
@ -238,7 +238,7 @@ data DropRel b
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance (Backend b) => FromJSON (DropRel b) where
|
instance (Backend b) => FromJSON (DropRel b) where
|
||||||
parseJSON = withObject "drop relationship" $ \o ->
|
parseJSON = withObject "DropRel" $ \o ->
|
||||||
DropRel
|
DropRel
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
@ -306,7 +306,7 @@ deriving instance (Backend b) => Show (SetRelComment b)
|
|||||||
deriving instance (Backend b) => Eq (SetRelComment b)
|
deriving instance (Backend b) => Eq (SetRelComment b)
|
||||||
|
|
||||||
instance (Backend b) => FromJSON (SetRelComment b) where
|
instance (Backend b) => FromJSON (SetRelComment b) where
|
||||||
parseJSON = withObject "set relationship comment" $ \o ->
|
parseJSON = withObject "SetRelComment" $ \o ->
|
||||||
SetRelComment
|
SetRelComment
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
|
@ -25,7 +25,7 @@ data RenameRel b
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance (Backend b) => FromJSON (RenameRel b) where
|
instance (Backend b) => FromJSON (RenameRel b) where
|
||||||
parseJSON = withObject "rename relationship" $ \o ->
|
parseJSON = withObject "RenameRel" $ \o ->
|
||||||
RenameRel
|
RenameRel
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
|
@ -72,7 +72,7 @@ data DeleteRemoteRelationship (b :: BackendType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance Backend b => FromJSON (DeleteRemoteRelationship b) where
|
instance Backend b => FromJSON (DeleteRemoteRelationship b) where
|
||||||
parseJSON = withObject "delete remote relationship" $ \o ->
|
parseJSON = withObject "DeleteRemoteRelationship" $ \o ->
|
||||||
DeleteRemoteRelationship
|
DeleteRemoteRelationship
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
|
@ -88,7 +88,7 @@ data TrackFunctionV2 (b :: BackendType) = TrackFunctionV2
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance Backend b => FromJSON (TrackFunctionV2 b) where
|
instance Backend b => FromJSON (TrackFunctionV2 b) where
|
||||||
parseJSON = withObject "track function" $ \o ->
|
parseJSON = withObject "TrackFunctionV2" $ \o ->
|
||||||
TrackFunctionV2
|
TrackFunctionV2
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "function"
|
<*> o .: "function"
|
||||||
@ -202,7 +202,7 @@ data FunctionPermissionArgument b = FunctionPermissionArgument
|
|||||||
|
|
||||||
instance (Backend b) => FromJSON (FunctionPermissionArgument b) where
|
instance (Backend b) => FromJSON (FunctionPermissionArgument b) where
|
||||||
parseJSON v =
|
parseJSON v =
|
||||||
flip (withObject "function permission") v $ \o ->
|
flip (withObject "FunctionPermissionArgument") v $ \o ->
|
||||||
FunctionPermissionArgument
|
FunctionPermissionArgument
|
||||||
<$> o .: "function"
|
<$> o .: "function"
|
||||||
<*> o .:? "source" .!= defaultSource
|
<*> o .:? "source" .!= defaultSource
|
||||||
|
@ -35,7 +35,7 @@ data AddSource b
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance (Backend b) => FromJSON (AddSource b) where
|
instance (Backend b) => FromJSON (AddSource b) where
|
||||||
parseJSON = withObject "add source" $ \o ->
|
parseJSON = withObject "AddSource" $ \o ->
|
||||||
AddSource
|
AddSource
|
||||||
<$> o .: "name"
|
<$> o .: "name"
|
||||||
<*> o .: "configuration"
|
<*> o .: "configuration"
|
||||||
@ -121,7 +121,7 @@ data DropSource
|
|||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
instance FromJSON DropSource where
|
instance FromJSON DropSource where
|
||||||
parseJSON = withObject "drop source" $ \o ->
|
parseJSON = withObject "DropSource" $ \o ->
|
||||||
DropSource <$> o .: "name" <*> o .:? "cascade" .!= False
|
DropSource <$> o .: "name" <*> o .:? "cascade" .!= False
|
||||||
|
|
||||||
runDropSource
|
runDropSource
|
||||||
|
@ -71,7 +71,7 @@ deriving instance (Backend b) => Eq (TrackTable b)
|
|||||||
instance (Backend b) => FromJSON (TrackTable b) where
|
instance (Backend b) => FromJSON (TrackTable b) where
|
||||||
parseJSON v = withOptions v <|> withoutOptions
|
parseJSON v = withOptions v <|> withoutOptions
|
||||||
where
|
where
|
||||||
withOptions = withObject "track table" \o -> TrackTable
|
withOptions = withObject "TrackTable" \o -> TrackTable
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
<*> o .:? "is_enum" .!= False
|
<*> o .:? "is_enum" .!= False
|
||||||
@ -85,7 +85,7 @@ data SetTableIsEnum
|
|||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
instance FromJSON SetTableIsEnum where
|
instance FromJSON SetTableIsEnum where
|
||||||
parseJSON = withObject "set table is enum" $ \o ->
|
parseJSON = withObject "SetTableIsEnum" $ \o ->
|
||||||
SetTableIsEnum
|
SetTableIsEnum
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
@ -101,7 +101,7 @@ deriving instance (Backend b) => Show (UntrackTable b)
|
|||||||
deriving instance (Backend b) => Eq (UntrackTable b)
|
deriving instance (Backend b) => Eq (UntrackTable b)
|
||||||
|
|
||||||
instance (Backend b) => FromJSON (UntrackTable b) where
|
instance (Backend b) => FromJSON (UntrackTable b) where
|
||||||
parseJSON = withObject "untrack table" $ \o ->
|
parseJSON = withObject "UntrackTable" $ \o ->
|
||||||
UntrackTable
|
UntrackTable
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
@ -219,7 +219,7 @@ data TrackTableV2 b
|
|||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
instance (Backend b) => FromJSON (TrackTableV2 b) where
|
instance (Backend b) => FromJSON (TrackTableV2 b) where
|
||||||
parseJSON = withObject "track table" $ \o -> do
|
parseJSON = withObject "TrackTableV2" $ \o -> do
|
||||||
table <- parseJSON $ Object o
|
table <- parseJSON $ Object o
|
||||||
configuration <- o .:? "configuration" .!= emptyTableConfig
|
configuration <- o .:? "configuration" .!= emptyTableConfig
|
||||||
pure $ TrackTableV2 table configuration
|
pure $ TrackTableV2 table configuration
|
||||||
@ -250,7 +250,7 @@ data SetTableCustomization b
|
|||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
instance (Backend b) => FromJSON (SetTableCustomization b) where
|
instance (Backend b) => FromJSON (SetTableCustomization b) where
|
||||||
parseJSON = withObject "set table customization" $ \o ->
|
parseJSON = withObject "SetTableCustomization" $ \o ->
|
||||||
SetTableCustomization
|
SetTableCustomization
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
@ -265,7 +265,7 @@ data SetTableCustomFields
|
|||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
instance FromJSON SetTableCustomFields where
|
instance FromJSON SetTableCustomFields where
|
||||||
parseJSON = withObject "set table custom fields" $ \o ->
|
parseJSON = withObject "SetTableCustomFields" $ \o ->
|
||||||
SetTableCustomFields
|
SetTableCustomFields
|
||||||
<$> o .:? "source" .!= defaultSource
|
<$> o .:? "source" .!= defaultSource
|
||||||
<*> o .: "table"
|
<*> o .: "table"
|
||||||
|
@ -16,8 +16,10 @@ module Hasura.Server.API.Backend where
|
|||||||
import Hasura.Prelude
|
import Hasura.Prelude
|
||||||
|
|
||||||
import qualified Data.Aeson.Types as J
|
import qualified Data.Aeson.Types as J
|
||||||
|
import qualified Data.Text as T
|
||||||
|
|
||||||
import Data.Aeson ((<?>))
|
import Data.Aeson ((<?>))
|
||||||
|
import Data.Aeson.Types (modifyFailure)
|
||||||
|
|
||||||
import Hasura.RQL.Types.Backend
|
import Hasura.RQL.Types.Backend
|
||||||
import Hasura.SQL.AnyBackend
|
import Hasura.SQL.AnyBackend
|
||||||
@ -45,7 +47,14 @@ commandParser expected constructor provided arguments =
|
|||||||
-- instance backtracks: if we used 'fail', we would not be able to distinguish between "this is
|
-- instance backtracks: if we used 'fail', we would not be able to distinguish between "this is
|
||||||
-- the correct branch, the name matches, but the argument fails to parse, we must fail" and "this
|
-- the correct branch, the name matches, but the argument fails to parse, we must fail" and "this
|
||||||
-- is not the command we were expecting here, it is fine to continue with another".
|
-- is not the command we were expecting here, it is fine to continue with another".
|
||||||
whenMaybe (expected == provided) $ constructor <$> (J.parseJSON arguments <?> J.Key "args")
|
whenMaybe (expected == provided) $
|
||||||
|
modifyFailure withDetails $ constructor <$> (J.parseJSON arguments <?> J.Key "args")
|
||||||
|
where
|
||||||
|
withDetails internalErrorMessage = intercalate "\n"
|
||||||
|
[ "Error when parsing command " <> T.unpack expected <> "."
|
||||||
|
, "See our documentation at https://hasura.io/docs/latest/graphql/core/api-reference/metadata-api/index.html#metadata-apis."
|
||||||
|
, "Internal error message: " <> internalErrorMessage
|
||||||
|
]
|
||||||
|
|
||||||
sourceCommands, tableCommands, tablePermissionsCommands, functionCommands,
|
sourceCommands, tableCommands, tablePermissionsCommands, functionCommands,
|
||||||
functionPermissionsCommands, relationshipCommands, remoteRelationshipCommands, eventTriggerCommands
|
functionPermissionsCommands, relationshipCommands, remoteRelationshipCommands, eventTriggerCommands
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
status: 400
|
status: 400
|
||||||
response:
|
response:
|
||||||
path: $.args.transform.content_type
|
path: $.args.transform.content_type
|
||||||
error: Invalid ContentType
|
error: "Error when parsing command create_event_trigger.\nSee our documentation at https://hasura.io/docs/latest/graphql/core/api-reference/metadata-api/index.html#metadata-apis.\nInternal error message: Invalid ContentType"
|
||||||
code: parse-failed
|
code: parse-failed
|
||||||
query:
|
query:
|
||||||
type: pg_create_event_trigger
|
type: pg_create_event_trigger
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
status: 400
|
status: 400
|
||||||
response:
|
response:
|
||||||
path: $.args.transform.request_headers.remove_headers[0]
|
path: $.args.transform.request_headers.remove_headers[0]
|
||||||
error: 'Restricted Header: Content-Type'
|
error: "Error when parsing command create_event_trigger.\nSee our documentation at https://hasura.io/docs/latest/graphql/core/api-reference/metadata-api/index.html#metadata-apis.\nInternal error message: Restricted Header: Content-Type"
|
||||||
code: parse-failed
|
code: parse-failed
|
||||||
query:
|
query:
|
||||||
type: pg_create_event_trigger
|
type: pg_create_event_trigger
|
||||||
|
@ -346,7 +346,7 @@ class TestGraphQLQueryBasicCitus:
|
|||||||
def test_create_invalid_fkey_relationship(self, hge_ctx, transport):
|
def test_create_invalid_fkey_relationship(self, hge_ctx, transport):
|
||||||
st_code, resp = hge_ctx.v1metadataq_f(self.dir() + '/setup_invalid_fkey_relationship.yaml')
|
st_code, resp = hge_ctx.v1metadataq_f(self.dir() + '/setup_invalid_fkey_relationship.yaml')
|
||||||
assert st_code == 400, resp
|
assert st_code == 400, resp
|
||||||
assert resp['error'] == "Expecting object { table, columns }."
|
assert resp['error'] == "Error when parsing command create_array_relationship.\nSee our documentation at https://hasura.io/docs/latest/graphql/core/api-reference/metadata-api/index.html#metadata-apis.\nInternal error message: Expecting object { table, columns }."
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def dir(cls):
|
def dir(cls):
|
||||||
@ -574,7 +574,7 @@ class TestGraphQLQueryBoolExpBasicMSSQL:
|
|||||||
def test_create_invalid_fkey_relationship(self, hge_ctx, transport):
|
def test_create_invalid_fkey_relationship(self, hge_ctx, transport):
|
||||||
st_code, resp = hge_ctx.v1metadataq_f(self.dir() + '/setup_invalid_fkey_relationship_mssql.yaml')
|
st_code, resp = hge_ctx.v1metadataq_f(self.dir() + '/setup_invalid_fkey_relationship_mssql.yaml')
|
||||||
assert st_code == 400, resp
|
assert st_code == 400, resp
|
||||||
assert resp['error'] == "Expecting object { table, columns }."
|
assert resp['error'] == "Error when parsing command create_array_relationship.\nSee our documentation at https://hasura.io/docs/latest/graphql/core/api-reference/metadata-api/index.html#metadata-apis.\nInternal error message: Expecting object { table, columns }."
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def dir(cls):
|
def dir(cls):
|
||||||
|
Loading…
Reference in New Issue
Block a user