Skip to content

Update documentation with guidance on the use of aggregates and projections with Spring Data #264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 113 additions & 1 deletion spring-graphql-docs/src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
= Spring for GraphQL Documentation
Brian Clozel; Andreas Marek; Rossen Stoyanchev
Brian Clozel; Andreas Marek; Rossen Stoyanchev; Mark Paluch
include::attributes.adoc[]


Expand Down Expand Up @@ -480,6 +480,58 @@ 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.

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]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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]
not be `null`, depending on the operation result. A plain, https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections.interfaces.closed[closed interface projection]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

query is here the database query.

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.



[[data-querydsl]]
=== Querydsl

Expand Down Expand Up @@ -607,6 +659,36 @@ building a `QuerydslDataFetcher` you will need to use builder methods to apply i
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.

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
`DataFetcher` producing the target type:

[source,java,indent=0,subs="verbatim,quotes"]
----
class Account {

String name, identifier, description;

Person owner;
}

interface AccountProjection {

String getName();

String getIdentifier();
}

// For single result queries
DataFetcher<AccountProjection> dataFetcher =
QuerydslDataFetcher.builder(repository).projectAs(AccountProjection.class).single();

// For multi-result queries
DataFetcher<Iterable<AccountProjection>> dataFetcher =
QuerydslDataFetcher.builder(repository).projectAs(AccountProjection.class).many();
----



[[data-querydsl-registration]]
==== Auto Registration
Expand Down Expand Up @@ -685,6 +767,36 @@ it is supported, so no extra setup is required to enable it.
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.

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
`DataFetcher` producing the target type:

[source,java,indent=0,subs="verbatim,quotes"]
----
class Account {

String name, identifier, description;

Person owner;
}

interface AccountProjection {

String getName();

String getIdentifier();
}

// For single result queries
DataFetcher<AccountProjection> dataFetcher =
QueryByExampleDataFetcher.builder(repository).projectAs(AccountProjection.class).single();

// For multi-result queries
DataFetcher<Iterable<AccountProjection>> dataFetcher =
QueryByExampleDataFetcher.builder(repository).projectAs(AccountProjection.class).many();
----



[[data-querybyexample-registration]]
==== Auto Registration
Expand Down