I know this might feel like a duplicate of this.
When to use @RestController vs @RepositoryRestResource
But I have a few things which were not addressed in that question.
With @RepositoryRestResource
, every method is by default exposed. Which I feel is a bit annoying. Correct me if I am wrong here. For example in the below case
@RepositoryRestResource
public interface ProductRepository extends MongoRepository<Product, String> {}
If I want only findAll() and findOne() to be exposed and not any other methods, especially delete. To achieve this I need to do something like this
@RepositoryRestResource
public interface ProductRepository extends MongoRepository<Product, String> {
@RestResource(exported = false)
@Override
default void delete(String s) {
}
@RestResource(exported = false)
@Override
default void delete(Product product) {
}
@RestResource(exported = false)
@Override
default void delete(Iterable<? extends Product> iterable) {
}
@RestResource(exported = false)
@Override
default void deleteAll() {
}
}
Which I feel is really lot of unwanted code. This is much better to do with Rest Controller approach
I believe it is better to return any value from REST endpoints using ResponseEntity. But with spring-data-rest approach, I am not sure how to do it.
I could not find any way to unit test(Not IT) REST endpoints exposed by the RepositoryRestResource. But with REST controller approach, I can test my REST endpoints using MockServletContext
, MockMvc
, MockMvcBuilders
Given all these, is it still advantageous to use sping-data-rest(except for HATEOS)?
please clarify
@RepositoryRestResource is used to set options on the public Repository interface - it will automatically create endpoints as appropriate based on the type of Repository that is being extended (i.e. CrudRepository/PagingAndSortingRepository/etc).
In this article, we had a look at Spring Data Rest, which is a framework used to build REST services around Spring Data repositories. It is ideal to use with simple applications or prototypes.
Then it uses the @RepositoryRestResource annotation to direct Spring MVC to create RESTful endpoints at /people . @RepositoryRestResource is not required for a repository to be exported. It is used only to change the export details, such as using /people instead of the default value of /persons .
The spring-data-rest-webmvc is the project describing the main concepts of spring-data-rest which is the one of the main spring modules. In most cases one will use spring-data-rest dependency for his/her project.
Spring-data-rest is about providing REST endpoints for data repositories and it does provides solid REST with all bells and whistles including ALPS metadata, search endpoints, etc. This usually covers most use cases and provides basis for customisations.
Here're some hints.
Regarding p.1) - Customising exported resources and methods.
You do not need to put @RestResource(exported = false)
on all delete(...)
methods because only one is actually exported: void delete(Product entity)
. Look into relevant documentation chapter and the source code. If i do not miss something, you just need to provide these:
findAll(Pageable)
findOne(id)
save(Entity)
delete(Entity)
A note about exported repository methods. Sometimes it's easier to extend a very basic (empty) Repository<Product, String>
repository interface and provide only methods you allow on the repository, for example:
@RepositoryRestResource
public interface ProductRepository extends Repository<Product, String> {
long count();
Page<Product> findAll(Pageable pageable);
Product findOne(String entity);
<S extends Product> S save(S entity);
}
Regarding a custom controller. To customise a default behaviour the easiest is to annotate controllers with @RespositoryRestController
. Check-out docs and look into RepositoryEntityController.java - that's the default controller.
Regarding p.2) Returning ResponseEntity from controllers
It's very straingforward. You can wrap entity into Resource<T>
(e.g. using a PersistentEntityResourceAssembler
) and create a ResponseEntity
with it. See RepositoryEntityController.java and some examples, like spring-restbucks.
Regarding p.3) - Testing rest endpoints
REST endpoints that expose the RepositoryRestResource are implemented in the RepositoryEntityController
(part of the spring-data-rest).
If you implement your own custom controller, you can add unit tests as usual but things get more complex if you use PersistentEntityResourceAssembler
.
Unit test example:
public class FooControllerTests {
@Mock
PersistentEntityResourceAssembler assembler;
@Mock
PersistentEntityResourceAssemblerArgumentResolver assemblerResolver;
@Mock
PersistentEntity<Foo, ?> entity;
@InjectMocks
FooController fooController;
@Mock
FooService fooService;
private MockMvc mockMvc;
@Rule
public MockitoRule rule = MockitoJUnit.rule();
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(fooController)
.setCustomArgumentResolvers(assemblerResolver)
.build();
}
@Test
public void test_GetItem_Success() throws Exception {
final Foo foo = new Foo();
when(fooService.findOne(1)).thenReturn(foo);
when(assemblerResolver.supportsParameter(any())).thenReturn(true);
when(assemblerResolver.resolveArgument(any(), any(), any(), any())).thenReturn(assembler);
when(assembler.toResource(foo))
.thenReturn(PersistentEntityResource.build(foo, entity).build());
this.mockMvc.perform(get("/foo/1")).andExpect(status().isOk());
}
}
See also "Building REST services with Spring" tutorial.
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With