Reputation: 165
I'm using Spring boot 1.5.10 with spring-boot-starter-data-rest.
I created domain entities:
@Entity
public class User {
@Column
private long id;
@Column
private String firstName;
@Column
private String secondName;
@Column
private int age;
@Fetch(FetchMode.SELECT)
@ManyToOne(fetch = FetchType.LAZY, optional = false)
private Address address;
...
}
@Entity
public class Address {
@Column
private long id;
@Column
private String city;
@Column
private String street;
@Column
private String build;
...
}
And I've created repositories for this domain entities:
interface UserRepository extends JpaRepository<User, String> {
User getUserByFirstNameAndSecondName(String firstName, String secondName);
@RestResource(exported = false)
User getUserByAddress(Address address);
}
interface AddressRepository extends JpaRepository<Address, String> {
Address getAddressByStreet(String street);
}
After that I give next HATEOAS root endpoints:
{
"_links" : {
"users" : {
"href" : "http://localhost:8080/api/v1/users{?page,size,sort}",
"templated" : true
},
"address" : {
"href" : "http://localhost:8080/api/v1/address{?page,size,sort}",
"templated" : true
}
}
And if I navigate to http://localhost:8080/api/v1/users I'll get something like that:
{
"_links" : {
"getUserByFirstNameAndSecondName" : {
"href" : "http://localhost:8080/api/v1/users/search/getUserByFirstNameAndSecondName{?firstName, secondName ,projection}",
"templated" : true
},
"self" : {
"href" : "http://localhost:8081/api/v1/users/search"
}
}
}
But I want to add a new endpoint to "http://localhost:8080/api/v1/users/search" use a custom controller, with @RepositoryRestController, for example:
@RepositoryRestController
public class UserRestController {
private UserRepository userRepository;
@Autowired
public UserRestController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@RequestMapping("/users/search/getUserByStreetAddress")
public User getUserByStreetAddress(String street) {
Address address = new Address();
address.setStreet(street);
return userRepository.getUserByAddress(address);
}
}
But my controller doesn't add anything to existing endpoints. I've read How to add links to root resource in Spring Data REST? and this decision works fine for root endpoints but I want add getUserByStreetAddress endpoint to users/search and eventually get the following:
{
"_links" : {
"getUserByFirstNameAndSecondName" : {
"href" : "http://localhost:8080/api/v1/users/search/getUserByFirstNameAndSecondName{?firstName, secondName ,projection}",
"templated" : true
},
//Method from my custom controller added to http://localhost:8080/api/v1/users/search" endpoint
"getUserByStreetAddress" : {
"href" : "http://localhost:8080/api/v1/users/search/getUserByStreetAddress{?street ,projection}",
"templated" : true
},
"self" : {
"href" : "http://localhost:8080/api/v1/users/search"
}
}
}
Is it possible to do this?
Upvotes: 1
Views: 1551
Reputation: 3169
You need to implement a ResourceProcessor<RepositorySearchesResource>
and add the link manually.
// other imports here
import static org.springframework.hateoas.TemplateVariable.VariableType.REQUEST_PARAM;
@Component
public class RepositorySearchesResourceProcessor implements ResourceProcessor<RepositorySearchesResource> {
@Autowired
private RepositoryRestConfiguration restConfiguration;
@Override
public RepositorySearchesResource process(RepositorySearchesResource resource) {
// early exit if we're not dealing with a User resource
if (!User.class.equals(resource.getDomainType())) {
return resource;
}
// add a custom link to /users/search
String search = resource.getId().getHref();
List<TemplateVariable> list = new ArrayList<>;
list.add(new TemplateVariable("street", REQUEST_PARAM);
boolean addProjection = restConfiguration.getProjectionConfiguration().hasProjectionFor(Parameter.class);
if (addProjection) {
// should be "projection" unless you configured it differently
list.add(restConfiguration.getProjectionConfiguration().getParameterName());
}
TemplateVariables tvs = new TemplateVariables(list);
Link link = new Link(new UriTemplate(search + "/getUserByStreetAddress", tvs"), "getUserByStreetAddress");
resource.add(link);
return resource;
}
I put in the RepositoryRestConfiguration and UriTemplate, so as to give a hint about adding other rest parameters (pagination, sorting...) later if necessary.
Upvotes: 2