Read models over HTTP

A projection’s read models can be served over HTTP without a controller of your own, through Spring Data REST, or read in your own Spring MVC controllers. This page covers both for the in-memory, JPA and query stores.

Spring Data REST

Add spring-boot-starter-data-rest to the application, and its projection repositories are exported read-only, under the application’s own Spring Data REST detection strategy (with annotated, a repository without @RepositoryRestResource is not exported):

  • GET reads; every write answers 405 Method Not Allowed, for an in-memory or query repository and for the application’s own JPA repository over a read model alike;

  • a sort the store cannot run, or an id in a link that makes no id of the repository, answers 400 Bad Request;

  • a repository carrying @RepositoryRestResource(exported = false) is not exported;

  • an in-memory or query repository whose read model has no @ReadModelKey own id with a backing field is never exported, since Spring Data REST links an item by its id; see The read model’s own id.

These answers come from exception advice for Spring Data REST’s controllers, ordered just before Spring Data REST’s own; an advice of the application ordered earlier wins.

Spring MVC

An in-memory or query repository’s id that wraps a single value, such as AccountId(val value: UUID), a value class or a class of one scalar or enum property, is made from text in a path variable or a request parameter, and in a Spring Data REST link. A String-to-id Converter the application registers itself is used instead of the framework’s. It is a Converter bean for Spring MVC, and for a Spring Data REST link it is also added in a RepositoryRestConfigurer’s `configureConversionService. The application’s own JPA repositories follow Spring Data JPA’s rules.

With Spring Data web support, a controller parameter typed as the read model resolves through the repository’s findById, and is null when no read model has that id. Spring Boot sets the support up in a Spring MVC application with a Spring Data starter, such as spring-boot-starter-data-jpa or spring-boot-starter-data-rest; otherwise declare @EnableSpringDataWebSupport on a configuration class.

@RestController
class AccountSummaryController {

    @GetMapping("/accounts/{id}")
    fun summary(@PathVariable("id") summary: AccountSummary?): AccountSummary =
        summary ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
}

The read model is that of an in-memory projection with an AccountSummaryRepository, as in In-memory store. The path variable is read as the repository’s id, AccountId, and the summary is looked up by it.