Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rest Controllers vs spring-data-rest RepositoryRestResource

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.

  1. 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

  1. 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.

  2. 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

like image 483
pvpkiran Avatar asked Mar 22 '17 20:03

pvpkiran


People also ask

When should I use RepositoryRestResource?

@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).

Should we use Spring data rest?

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.

What is @RepositoryRestResource in spring boot?

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 .

What is Spring data rest Webmvc?

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.


1 Answers

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.

like image 70
aux Avatar answered Oct 25 '22 21:10

aux