Validate the subscription root
…not to be an introspection field.
This commit is contained in:
parent
2dcefff76a
commit
7ea76865e6
@ -9,6 +9,8 @@ and this project adheres to
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Changed
|
### Changed
|
||||||
- Remove deprecated 'gql' quasi quoter.
|
- Remove deprecated 'gql' quasi quoter.
|
||||||
|
- Validate the subscription root not to be an introspection field
|
||||||
|
(`singleFieldSubscriptionsRule`).
|
||||||
|
|
||||||
## [1.4.0.0] - 2024-10-26
|
## [1.4.0.0] - 2024-10-26
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -137,25 +137,28 @@ singleFieldSubscriptionsRule :: forall m. Rule m
|
|||||||
singleFieldSubscriptionsRule = OperationDefinitionRule $ \case
|
singleFieldSubscriptionsRule = OperationDefinitionRule $ \case
|
||||||
Full.OperationDefinition Full.Subscription name' _ _ rootFields location' -> do
|
Full.OperationDefinition Full.Subscription name' _ _ rootFields location' -> do
|
||||||
groupedFieldSet <- evalStateT (collectFields rootFields) HashSet.empty
|
groupedFieldSet <- evalStateT (collectFields rootFields) HashSet.empty
|
||||||
case HashSet.size groupedFieldSet of
|
case HashSet.toList groupedFieldSet of
|
||||||
1 -> lift mempty
|
[rootName]
|
||||||
_
|
| Text.isPrefixOf "__" rootName -> makeError location' name'
|
||||||
| Just name <- name' -> pure $ Error
|
"exactly one top level field, which must not be an introspection field."
|
||||||
{ message = concat
|
| otherwise -> lift mempty
|
||||||
[ "Subscription \""
|
[] -> makeError location' name' "exactly one top level field."
|
||||||
, Text.unpack name
|
_ -> makeError location' name' "only one top level field."
|
||||||
, "\" must select only one top level field."
|
|
||||||
]
|
|
||||||
, locations = [location']
|
|
||||||
}
|
|
||||||
| otherwise -> pure $ Error
|
|
||||||
{ message = errorMessage
|
|
||||||
, locations = [location']
|
|
||||||
}
|
|
||||||
_ -> lift mempty
|
_ -> lift mempty
|
||||||
where
|
where
|
||||||
errorMessage =
|
makeError location' (Just operationName) errorLine = pure $ Error
|
||||||
"Anonymous Subscription must select only one top level field."
|
{ message = concat
|
||||||
|
[ "Subscription \""
|
||||||
|
, Text.unpack operationName
|
||||||
|
, "\" must select "
|
||||||
|
, errorLine
|
||||||
|
]
|
||||||
|
, locations = [location']
|
||||||
|
}
|
||||||
|
makeError location' Nothing errorLine = pure $ Error
|
||||||
|
{ message = "Anonymous Subscription must select " <> errorLine
|
||||||
|
, locations = [location']
|
||||||
|
}
|
||||||
collectFields = foldM forEach HashSet.empty
|
collectFields = foldM forEach HashSet.empty
|
||||||
forEach accumulator = \case
|
forEach accumulator = \case
|
||||||
Full.FieldSelection fieldSelection -> forField accumulator fieldSelection
|
Full.FieldSelection fieldSelection -> forField accumulator fieldSelection
|
||||||
|
@ -18,7 +18,7 @@ import qualified Language.GraphQL.AST.DirectiveLocation as DirectiveLocation
|
|||||||
import qualified Language.GraphQL.Type.In as In
|
import qualified Language.GraphQL.Type.In as In
|
||||||
import qualified Language.GraphQL.Type.Out as Out
|
import qualified Language.GraphQL.Type.Out as Out
|
||||||
import Language.GraphQL.Validate
|
import Language.GraphQL.Validate
|
||||||
import Test.Hspec (Spec, context, describe, it, shouldBe, shouldContain, xit)
|
import Test.Hspec (Spec, context, describe, it, shouldBe, shouldContain)
|
||||||
import Text.Megaparsec (parse, errorBundlePretty)
|
import Text.Megaparsec (parse, errorBundlePretty)
|
||||||
|
|
||||||
petSchema :: Schema IO
|
petSchema :: Schema IO
|
||||||
@ -206,14 +206,14 @@ spec =
|
|||||||
}
|
}
|
||||||
in validate queryString `shouldContain` [expected]
|
in validate queryString `shouldContain` [expected]
|
||||||
|
|
||||||
xit "rejects an introspection field as the subscription root" $
|
it "rejects an introspection field as the subscription root" $
|
||||||
let queryString = "subscription sub {\n\
|
let queryString = "subscription sub {\n\
|
||||||
\ __typename\n\
|
\ __typename\n\
|
||||||
\}"
|
\}"
|
||||||
expected = Error
|
expected = Error
|
||||||
{ message =
|
{ message =
|
||||||
"Subscription \"sub\" must select only one top \
|
"Subscription \"sub\" must select exactly one top \
|
||||||
\level field."
|
\level field, which must not be an introspection field."
|
||||||
, locations = [AST.Location 1 1]
|
, locations = [AST.Location 1 1]
|
||||||
}
|
}
|
||||||
in validate queryString `shouldContain` [expected]
|
in validate queryString `shouldContain` [expected]
|
||||||
|
Loading…
Reference in New Issue
Block a user