diff --git a/spring-graphql-docs/src/docs/asciidoc/index.adoc b/spring-graphql-docs/src/docs/asciidoc/index.adoc index 5d2b82a5..afc3fe1f 100644 --- a/spring-graphql-docs/src/docs/asciidoc/index.adoc +++ b/spring-graphql-docs/src/docs/asciidoc/index.adoc @@ -480,55 +480,13 @@ assertThat(books.get(0).getName()).isEqualTo("..."); [[data]] == Data Integration -Spring for GraphQL is, in contrast to other GraphQL technologies that surface persistent -data, not a data gateway that translates GraphQL queries into SQL or JSON queries. -Instead, Spring for GraphQL is an API gateway that leverages existing Spring technology -following common programming models to expose underlying data sources through GraphQL. +Spring for GraphQL lets you leverage existing Spring technology, following common +programming models to expose underlying data sources through GraphQL. -Domain-driven design is the suggested approach to manage complexity when using Spring Data. -So by design, a GraphQL API built on top of Spring Data can leverage only what's already -provided by an application. -It, therefore, must adhere to the constraints of an aggregate. -By definition, an aggregate is only valid if it is loaded in its entirety. -Partially loaded aggregates may impose a limitation on aggregate functionality. - -With Spring Data you can choose whether you want to let your aggregate participate as -an underlying data model to be directly exposed as a GraphQL result, or whether you want to -apply projections to your data model before returning it as a GraphQL operation result. - -The advantage of using aggregates is that you do not require additional code to expose -data through repositories. When processing a GraphQL operation, the integration layer -transforms the field selection set into property paths. It provides these hints of which -properties to materialize to the underlying Spring Data module that limits the field -(or column) selection. - -Sometimes, an already reduced set of fields can be useful when exposing data. Also, some -arrangements might require transformations to be applied before data is returned for a -GraphQL operation. Spring Data supports for these scenarios projections: Interface and DTO -Projections. - -Interface projections define a fixed set of properties to expose. Properties may or may -not be `null`, depending on the query result. A plain, https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections.interfaces.closed[closed interface projection] -can be useful if you cannot partially materialize the aggregate object but you still -want to expose a subset of properties. - -You can use interface projections to apply a lightweight set of data transformations, -such as concatenations, computations or applying a static function to a property. - -https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections.interfaces.open[Open projections] -leverage Spring's `@Value` annotation and -{spring-framework-ref-docs}/core.html#expressions[SpEL expressions]for transformations. - -In both cases, interface projections define which properties to load from the underlying -data source. - -DTO projections offer the highest possible level of customization as you can place your -transformation code either in the constructor or the getter method. - -DTO projections materialize from a query where the individual properties are -determined by the projection itself. DTO projections are commonly used with full-args -constructors (e.g. Java records) and therefore they can only be constructed if all -required fields (or columns) are part of the database query result. +This section discusses an integration layer for Spring Data that provides an easy way to +adapt a Querydsl or a Query by Example repository to a `DataFetcher`, including the +option for automated detection and GraphQL Query registration for repositories marked +with `@GraphQlRepository`. @@ -655,9 +613,12 @@ A repository may itself be an instance of `QuerydslBinderCustomizer`. This is au and transparently applied during <>. However, when manually building a `QuerydslDataFetcher` you will need to use builder methods to apply it. -`QuerydslDataFetcher` supports -https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections[interface and DTO projections] -to transform query results before returning these for further GraphQL processing. +`QuerydslDataFetcher` supports interface and DTO projections to transform query results +before returning these for further GraphQL processing. + +TIP: To learn what projections are, please refer to the +https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections[Spring Data docs]. +To understand how to use projections in GraphQL, please see <>. To use Spring Data projections with Querydsl repositories, create either a projection interface or a target DTO class and configure it through the `projectAs` method to obtain a @@ -691,7 +652,7 @@ or a target DTO class and configure it through the `projectAs` method to obtain [[data-querydsl-registration]] -==== Auto Registration +==== Auto-Registration If a repository is annotated with `@GraphQlRepository`, it is automatically registered for queries that do not already have a registered `DataFetcher` and whose return type @@ -713,7 +674,6 @@ detects `@GraphQlRepository` beans and uses them to initialize the - [[data-querybyexample]] === Query by Example @@ -763,9 +723,12 @@ it is supported, so no extra setup is required to enable it. [[data-querybyexample-customizations]] ==== Customizations -`QueryByExampleDataFetcher` supports -https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections[interface and DTO projections] -to transform query results before returning these for further GraphQL processing. +`QueryByExampleDataFetcher` supports interface and DTO projections to transform query +results before returning these for further GraphQL processing. + +TIP: To learn what projections are, please refer to the +https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections[Spring Data docs]. +To understand how to use projections in GraphQL, please see <>. To use Spring Data projections with Query by Example repositories, create either a projection interface or a target DTO class and configure it through the `projectAs` method to obtain a @@ -797,9 +760,8 @@ or a target DTO class and configure it through the `projectAs` method to obtain ---- - [[data-querybyexample-registration]] -==== Auto Registration +==== Auto-Registration If a repository is annotated with `@GraphQlRepository`, it is automatically registered for queries that do not already have a registered `DataFetcher` and whose return type @@ -818,6 +780,58 @@ detects `@GraphQlRepository` beans and uses them to initialize the +[[data-projections]] +=== Selection Set vs Projections + +A common question that arises is, how GraphQL selection sets compare to +https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections[Spring Data projections] +and what roles do each play? + +The short answer is that Spring for GraphQL is not a data gateway that translates GraphQL +queries directly into SQL or JSON queries. Instead, it lets you leverage existing Spring +technology and does not assume a one for one mapping between the GraphQL schema and the +underlying data. That is why is there is room for both client-driven selection and for +server-side transformation of the data model. + +To understand better, consider that Spring Data promotes domain-driven (DDD) design as +the recommended approach to manage complexity in the data layer. In DDD, it is important +to adhere to the constraints of an aggregate. By definition an aggregate is valid only if +loaded in its entirety, since a partially loaded aggregate may impose a limitation on +aggregate functionality. + +In Spring Data you can choose whether you want your aggregate be exposed as is, or +whether to apply projections to the data model before returning it. Sometimes it's enough +to do the former and by default, the <> and <> +integrations rely on the GraphQL field selection set to provide property path hints to +the underlying Spring Data module to limit the field (or column) selection. + +In other cases, it's useful to reduce or even transform the underlying data model in +order to adapt to the GraphQL schema, and Spring Data supports these through Interface +and DTO Projections. + +Interface projections define a fixed set of properties to expose. Properties may or may +not be `null`, depending on the data store query result. There are two kinds of interface +projections both of which define which properties to load from the underlying data source: + +- https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections.interfaces.closed[Closed interface projections] +are helpful if you cannot partially materialize the aggregate object, but you still +want to expose a subset of properties. +- https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections.interfaces.open[Open interface projections] +leverage Spring's `@Value` annotation and +{spring-framework-ref-docs}/core.html#expressions[SpEL] expressions to apply lightweight +data transformations, such as concatenations, computations, or to apply a static function +to a property. + +DTO projections offer the highest possible level of customization as you can place your +transformation code either in the constructor or the getter method. + +DTO projections materialize from a query where the individual properties are +determined by the projection itself. DTO projections are commonly used with full-args +constructors (e.g. Java records), and therefore they can only be constructed if all +required fields (or columns) are part of the database query result. + + + [[controllers]] == Annotated Controllers