@@ -754,3 +754,67 @@ Supported return types are listed below:
754
754
| For asynchronous resolution where `<T>` is one of the supported, synchronous, return types.
755
755
756
756
|===
757
+
758
+
759
+
760
+ [[controllers.namespacing]]
761
+ == Namespacing
762
+
763
+ At the schema level, query and mutation operations are defined directly under the `Query` and `Mutation` types.
764
+ Rich GraphQL APIs can define dozens of operation sunder those types, making it harder to explore the API and separate concerns.
765
+ You can choose to https://www.apollographql.com/docs/technotes/TN0012-namespacing-by-separation-of-concern/[define Namespaces in your GraphQL schema].
766
+ While there are some caveats with this approach, you can implement this pattern with Spring for GraphQL annotated controllers.
767
+
768
+ With namespacing, your GraphQL schema can, for example, nest query operations under top-level types, instead of listing them directly under `Query`.
769
+ Here, we will define `MusicQueries` and `UserQueries` types and make them available under `Query`:
770
+
771
+ [source,json,subs="verbatim,quotes"]
772
+ ----
773
+ include::ROOT:{include-resources}/controllers/namespaces.graphqls[]
774
+ ----
775
+
776
+ A GraphQL client would use the `album` query like this:
777
+
778
+ [source,graphql,subs="verbatim,quotes"]
779
+ ----
780
+ {
781
+ music {
782
+ album(id: 42) {
783
+ id
784
+ title
785
+ }
786
+ }
787
+ }
788
+ ----
789
+
790
+ And get the following response:
791
+
792
+ [source,json,subs="verbatim,quotes"]
793
+ ----
794
+ {
795
+ "data": {
796
+ "music": {
797
+ "album": {
798
+ "id": "42",
799
+ "title": "Spring for GraphQL"
800
+ }
801
+ }
802
+ }
803
+ }
804
+ ----
805
+
806
+
807
+ This can be implemented in a `@Controller` with the following pattern:
808
+
809
+ include-code::MusicController[]
810
+ <1> Annotate the controller with `@SchemaMapping` and a `typeName` attribute, to avoid repeating it on methods
811
+ <2> Define a `@QueryMapping` for the "music" namespace
812
+ <3> The "music" query returns an "empty" record, but could also return an empty map
813
+ <4> Queries are now declared as fields under the "MusicQueries" type
814
+
815
+ Instead of declaring wrapping types ("MusicQueries", "UserQueries") explicitly in controllers,
816
+ you can choose to configure them with the runtime wiring using a `GraphQlSourceBuilderCustomizer` with Spring Boot:
817
+
818
+ include-code::NamespaceConfiguration[]
819
+ <1> List all the wrapper types for the "Query" type
820
+ <2> Manually declare data fetchers for each of them, returning an empty Map
0 commit comments