6

I would like to add a custom search endpoint to my existing user repository.

My user Repository looks like this:

@RepositoryRestResource(collectionResourceRel="users", path="users")
public interface UserRepository extends PagingAndSortingRepository<User, Long>{

    User findByUsername(String username);
}

The custom controller:

@BasePathAwareController 
@RequestMapping("users/search")
public class CustomController implements ResourceProcessor<RepositorySearchesResource>, ResourceAssembler<User, Resource<User>> {
    @Autowired
    UserRepository userReposiotry;
    @Autowired
    private EntityLinks entityLinks;

    @RequestMapping(value = "findFirst", produces = "application/json")
    @ResponseBody
    public ResponseEntity<Resource<User>> findFirstUser() {
          Resource<User> resource = toResource(userReposiotry.findOne(1L));
          return new ResponseEntity<Resource<User>>(resource, HttpStatus.OK);
    }

    @Override
    public RepositorySearchesResource process(RepositorySearchesResource resource) {
        LinkBuilder lb = entityLinks.linkFor(User.class, "username");
        resource.add(new Link(lb.toString() + "/search/findFirst", "findFirst"));
        return resource;
    }

    @Override
    public Resource<User> toResource(User user) {
        Resource<User> resource = new Resource<User>(user);
        return resource;
    }
}

This returns the correct search endpoint for the users:

{
  "_links": {
    "findByUsername": {
      "href": "http://localhost:8080/api/users/search/findByUsername"
    },
    "self": {
      "href": "http://localhost:8080/api/users/search"
    },
    "findFirst": {
      "href": "http://localhost:8080/api/users/search/findFirst",
      "templated": true
    }
  }
}

But also for other endpoints like Invites:

{
  "_links": {
    "findUserByInvite": {
      "href": "http://localhost:8080/api/invites/search/findUserByInvite"
    },
    "self": {
      "href": "http://localhost:8080/api/invites/search"
    },
    "findFirst": {
      "href": "http://localhost:8080/api/invites/search/findFirst",
      "templated": true
    }
  }
}

How can this be restricted to the users only? Thanks

user1601401
  • 732
  • 1
  • 12
  • 25

2 Answers2

4

I assume your invites endpoint also returns a RepositorySearchesResource ?! Your ResourceProcessor is invoked whenever spring-data-rest serializes a RepositorySearchesResource. If you want different links for users and invites you have some alternatives:

  • use different return types for your search endpoints so you can have different ResourceProcessor implementations
  • put more logic inside your ResourceProcessor to differentiate if you are in your invites or users use case
Mathias Dpunkt
  • 11,594
  • 4
  • 45
  • 70
  • Hi, The invite is the same as the userRepository interface. Using your second suggestion I managed to do it by adding a if(resource.getDomainType() == User.class) into my RepositorySearchesResource process. But I have been wondering is there a better way to do it? Thanks – user1601401 Dec 02 '15 at 08:56
  • Hi, Can anyone say me the `ResourceProcessor` alternative in the most recent implementation of Spring? I know [some of the Class Names are changed](https://docs.spring.io/spring-hateoas/docs/current/reference/html/#migrate-to-1.0.changes.representation-models). But can't find something about `ResourceProcessor` there. – NAbdulla Sep 11 '20 at 12:02
0

Another way to do that is use ResponseBodyAdvice.

@ControllerAdvice
public class AllEntityBodyAdvice implements ResponseBodyAdvice {

    @Override
    public boolean supports(@NonNull MethodParameter returnType, @NonNull Class converterType) {
        System.out.println("In supports() method of " + getClass().getSimpleName());
        return true;
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        System.out.println("In beforeBodyWrite() method of " + getClass().getSimpleName());

        if (Objects.equals(request.getMethod(), HttpMethod.GET)) {
             // do sth
        }

        return body;
    }
}
Jess Chen
  • 3,136
  • 1
  • 26
  • 35