Create dedicated section on projections

Closes gh-264
This commit is contained in:
rstoyanchev
2022-01-20 16:28:13 +00:00
parent f34da2589b
commit 4a031ba519

View File

@@ -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 <<data-querydsl-registration>>. 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 <<data-projections>>.
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 <<data-projections>>.
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 <<data-querydsl>> and <<data-querybyexample>>
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