[[projections-excerpts]]
= Projections and Excerpts

Spring Data REST presents a default view of the domain model you export. However, sometimes, you may need to alter the view of that model for various reasons. This section covers how to define projections and excerpts to serve up simplified and reduced views of resources.

[[projections-excerpts.projections]]
== Projections

Consider the following domain model:

====
[source,java]
----
@Entity
public class Person {

  @Id @GeneratedValue
  private Long id;
  private String firstName, lastName;

  @OneToOne
  private Address address;
  …
}
----
====

The `Person` object in the preceding example has several attributes:

* `id` is the primary key.
* `firstName` and `lastName` are data attributes.
* `address` is a link to another domain object.

Now assume that we create a corresponding repository, as follows:

====
[source,java]
----
interface PersonRepository extends CrudRepository<Person, Long> {}
----
====

By default, Spring Data REST exports this domain object, including all of its attributes. `firstName` and `lastName` are exported as the plain data objects that they are. There are two options regarding the `address` attribute. One option is to also define a repository for `Address` objects, as follows:

====
[source,java]
----
interface AddressRepository extends CrudRepository<Address, Long> {}
----
====

In this situation, a `Person` resource renders the `address` attribute as a URI to its corresponding `Address` resource. If we were to look up "`Frodo`" in the system, we could expect to see a HAL document like this:

====
[source,javascript]
----
{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/persons/1"
    },
    "address" : {
      "href" : "http://localhost:8080/persons/1/address"
    }
  }
}
----
====

There is another way. If the `Address` domain object does not have its own repository definition, Spring Data REST includes the data fields inside the `Person` resource, as the following example shows:

====
[source,javascript]
----
{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "address" : {
    "street": "Bag End",
    "state": "The Shire",
    "country": "Middle Earth"
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/persons/1"
    }
  }
}
----
====

But what if you do not want `address` details at all? Again, by default, Spring Data REST exports all of its attributes (except the `id`). You can offer the consumer of your REST service an alternative by defining one or more projections. The following example shows a projection that does not include the address:

====
[source,java]
----
@Projection(name = "noAddresses", types = { Person.class }) <1>
interface NoAddresses { <2>

  String getFirstName(); <3>

  String getLastName(); <4>
}
----

<1> The `@Projection` annotation flags this as a projection. The `name` attribute provides
the name of the projection, which we cover in more detail shortly. The `types` attributes targets this projection to apply only to `Person` objects.
<2> It is a Java interface, making it declarative.
<3> It exports the `firstName`.
<4> It exports the `lastName`.
====

The `NoAddresses` projection only has getters for `firstName` and `lastName`, meaning that it does not serve up any address information. Assuming you have a separate repository for `Address` resources, the default view from Spring Data REST differs slightly from the previous representation, as the following example shows:

====
[source,javascript]
----
{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/persons/1{?projection}", <1>
      "templated" : true <2>
    },
    "address" : {
      "href" : "http://localhost:8080/persons/1/address"
    }
  }
}
----

<1> This resource has a new option: `{?projection}`.
<2> The `self` URI is a URI Template.
====

To view the projection to the resource, look up `http://localhost:8080/persons/1?projection=noAddresses`.

NOTE: The value supplied to the `projection` query parameter is the same as that specified in `@Projection(name = "noAddress")`. It has nothing to do with the name of the projection's interface.

You can have multiple projections.

NOTE: See xref:introduction/spring-data-rest-examples.adoc#spring-data-examples.projections[Projections] to see an example project. We encourage you to experiment with it.

Spring Data REST finds projection definitions as follows:

* Any `@Projection` interface found in the same package as your entity definitions (or one of its sub-packages) is registered.
* You can manually register a projection by using `RepositoryRestConfiguration.getProjectionConfiguration().addProjection(…)`.

In either case, the projection interface must have the `@Projection` annotation.

[[projections-excerpts.finding-projections]]
=== Finding Existing Projections

Spring Data REST exposes xref:metadata.adoc#metadata.alps[Application-Level Profile Semantics (ALPS)] documents, a micro metadata format. To view the ALPS metadata, follow the `profile` link exposed by the root resource. If you navigate down to the ALPS document for `Person` resources (which would be `/alps/persons`), you can find many details about `Person` resources. Projections are listed, along with the details about the `GET` REST transition, in blocks similar to the following example:

====
[source,javascript]
----
{ …
  "id" : "get-person", <1>
  "name" : "person",
  "type" : "SAFE",
  "rt" : "#person-representation",
  "descriptors" : [ {
    "name" : "projection", <2>
    "doc" : {
      "value" : "The projection that shall be applied when rendering the response. Acceptable values available in nested descriptors.",
      "format" : "TEXT"
    },
    "type" : "SEMANTIC",
    "descriptors" : [ {
      "name" : "noAddresses", <3>
      "type" : "SEMANTIC",
      "descriptors" : [ {
        "name" : "firstName", <4>
        "type" : "SEMANTIC"
      }, {
        "name" : "lastName", <4>
        "type" : "SEMANTIC"
      } ]
    } ]
  } ]
},
…
----

<1> This part of the ALPS document shows details about `GET` and `Person` resources.
<2> This part contais the `projection` options.
<3> This part contains the `noAddresses` projection.
<4> The actual attributes served up by this projection include `firstName` and `lastName`.
====

[NOTE]
====
Projection definitions are picked up and made available for clients if they are:

* Flagged with the `@Projection` annotation and located in the same package (or sub-package) of the domain type, OR
* Manually registered by using `RepositoryRestConfiguration.getProjectionConfiguration().addProjection(…)`.
====

[[projections-excerpts.projections.hidden-data]]
=== Bringing in Hidden Data

So far in this section, we have covered how projections can be used to reduce the information that is presented to the user. Projections can also bring in normally unseen data. For example, Spring Data REST ignores fields or getters that are marked up with `@JsonIgnore` annotations. Consider the following domain object:

====
[source,java]
----
@Entity
public class User {

	@Id @GeneratedValue
	private Long id;
	private String name;

	@JsonIgnore private String password; <1>

	private String[] roles;
  …
----

<1> Jackson's `@JsonIgnore` is used to prevent the `password` field from being serialized into JSON.
====

The `User` class in the preceding example can be used to store user information as well as integration with Spring Security. If you create a `UserRepository`, the `password` field would normally have been exported, which is not good. In the preceding example, we prevent that from happening by applying Jackson's `@JsonIgnore` on the `password` field.

NOTE: Jackson also does not serialize the field into JSON if `@JsonIgnore` is on the field's corresponding getter function.

However, projections introduce the ability to still serve this field. It is possible to create the following projection:

====
[source,java]
----
@Projection(name = "passwords", types = { User.class })
interface PasswordProjection {

  String getPassword();
}
----
====

If such a projection is created and used, it sidesteps the `@JsonIgnore` directive placed on `User.password`.

IMPORTANT: This example may seem a bit contrived, but it is possible, with a richer domain model and many projections, to accidentally leak such details. Since Spring Data REST cannot discern the sensitivity of such data, it is up to you to avoid such situations.

Projections can also generate virtual data. Imagine you had the following entity definition:

====
[source,java]
----
@Entity
public class Person {

  ...
  private String firstName;
  private String lastName;

  ...
}
----
====

You can create a projection that combines the two data fields in the preceding example together, as follows:

====
[source,java]
----
@Projection(name = "virtual", types = { Person.class })
public interface VirtualProjection {

  @Value("#{target.firstName} #{target.lastName}") <1>
  String getFullName();

}
----

<1> Spring's `@Value` annotation lets you plug in a SpEL expression that takes the target object and splices together its `firstName` and `lastName` attributes to render a read-only `fullName`.
====

[[projections-excerpts.excerpts]]
== Excerpts

An excerpt is a projection that is automatically applied to a resource collection. For example, you can alter the `PersonRepository` as follows:

====
[source,java]
----
@RepositoryRestResource(excerptProjection = NoAddresses.class)
interface PersonRepository extends CrudRepository<Person, Long> {}
----
====

The preceding example directs Spring Data REST to use the `NoAddresses` projection when embedding `Person` resources into collections or related resources.

NOTE: Excerpt projections are not automatically applied to single resources. They have to be applied deliberately. Excerpt projections are meant to provide a default preview of collection data but not when fetching individual resources. See https://stackoverflow.com/questions/30220333/why-is-an-excerpt-projection-not-applied-automatically-for-a-spring-data-rest-it[Why is an excerpt projection not applied automatically for a Spring Data REST item resource?] for a discussion on the subject.

In addition to altering the default rendering, excerpts have additional rendering options as shown in the next section.

[[projections-excerpts.excerpting-commonly-accessed-data]]
=== Excerpting Commonly Accessed Data

A common situation with REST services arises when you compose domain objects. For example, a `Person` is stored in one table and their related `Address` is stored in another. By default, Spring Data REST serves up the person's `address` as a URI the client must navigate. But if it is common for consumers to always fetch this extra piece of data, an excerpt projection can put this extra piece of data inline, saving you an extra `GET`. To do so, you can define another excerpt projection, as follows:

====
[source,java]
----
@Projection(name = "inlineAddress", types = { Person.class }) <1>
interface InlineAddress {

  String getFirstName();

  String getLastName();

  Address getAddress(); <2>
}
----

<1> This projection has been named `inlineAddress`.
<2> This projection adds `getAddress`, which returns the `Address` field. When used inside a projection, it causes the information to be included inline.
====

You can plug it into the `PersonRepository` definition, as follows:

====
[source,java]
----
@RepositoryRestResource(excerptProjection = InlineAddress.class)
interface PersonRepository extends CrudRepository<Person, Long> {}
----
====

Doing so causes the HAL document to appear as follows:

====
[source,javascript]
----
{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "address" : { <1>
    "street": "Bag End",
    "state": "The Shire",
    "country": "Middle Earth"
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/persons/1"
    },
    "address" : { <2>
      "href" : "http://localhost:8080/persons/1/address"
    }
  }
}
----

<1> The `address` data is directly included inline, so you do not have to navigate to get it.
<2> The link to the `Address` resource is still provided, making it still possible to navigate to its own resource.
====

Note that the preceding example is a mix of the examples shown earlier in this chapter. You may want to read back through them to follow the progression to the final example.

WARNING: Configuring `@RepositoryRestResource(excerptProjection=...)` for a repository alters the default behavior. This can potentially cause breaking changes to consumers of your service if you have already made a release.
