@@ -917,3 +917,67 @@ Supported return types are listed below:
917
917
| For asynchronous resolution where `<T>` is one of the supported, synchronous, return types.
918
918
919
919
|===
920
+
921
+
922
+
923
+ [[controllers.namespacing]]
924
+ == Namespacing
925
+
926
+ At the schema level, query and mutation operations are defined directly under the `Query` and `Mutation` types.
927
+ Rich GraphQL APIs can define dozens of operation sunder those types, making it harder to explore the API and separate concerns.
928
+ You can choose to https://www.apollographql.com/docs/technotes/TN0012-namespacing-by-separation-of-concern/[define Namespaces in your GraphQL schema].
929
+ While there are some caveats with this approach, you can implement this pattern with Spring for GraphQL annotated controllers.
930
+
931
+ With namespacing, your GraphQL schema can, for example, nest query operations under top-level types, instead of listing them directly under `Query`.
932
+ Here, we will define `MusicQueries` and `UserQueries` types and make them available under `Query`:
933
+
934
+ [source,json,subs="verbatim,quotes"]
935
+ ----
936
+ include::ROOT:{include-resources}/controllers/namespaces.graphqls[]
937
+ ----
938
+
939
+ A GraphQL client would use the `album` query like this:
940
+
941
+ [source,graphql,subs="verbatim,quotes"]
942
+ ----
943
+ {
944
+ music {
945
+ album(id: 42) {
946
+ id
947
+ title
948
+ }
949
+ }
950
+ }
951
+ ----
952
+
953
+ And get the following response:
954
+
955
+ [source,json,subs="verbatim,quotes"]
956
+ ----
957
+ {
958
+ "data": {
959
+ "music": {
960
+ "album": {
961
+ "id": "42",
962
+ "title": "Spring for GraphQL"
963
+ }
964
+ }
965
+ }
966
+ }
967
+ ----
968
+
969
+
970
+ This can be implemented in a `@Controller` with the following pattern:
971
+
972
+ include-code::MusicController[]
973
+ <1> Annotate the controller with `@SchemaMapping` and a `typeName` attribute, to avoid repeating it on methods
974
+ <2> Define a `@QueryMapping` for the "music" namespace
975
+ <3> The "music" query returns an "empty" record, but could also return an empty map
976
+ <4> Queries are now declared as fields under the "MusicQueries" type
977
+
978
+ Instead of declaring wrapping types ("MusicQueries", "UserQueries") explicitly in controllers,
979
+ you can choose to configure them with the runtime wiring using a `GraphQlSourceBuilderCustomizer` with Spring Boot:
980
+
981
+ include-code::NamespaceConfiguration[]
982
+ <1> List all the wrapper types for the "Query" type
983
+ <2> Manually declare data fetchers for each of them, returning an empty Map
0 commit comments