1. Introduction
Spring Data REST can remove a lot of boilerplate that’s natural to REST services.
In this tutorial, we’ll explore how to customize some of Spring Data REST’s HTTP binding defaults.
2. Spring Data REST Repository Fundamentals
To get started, let’s create an empty interface that extends the CrudRepository interface, specifying the type of our entity and the type of its primary key:
public interface UserRepository extends CrudRepository<WebsiteUser, Long> {}
By default, Spring generates all the mappings needed, configures each resource to be accessible via the appropriate HTTP methods, and returns the proper status codes.
If we don’t need all the resources defined in CrudRepository, we can extend the basic Repository interface and define only the resources we want:
public interface UserRepository extends Repository<WebsiteUser, Long> { void deleteById(Long aLong); }
Upon receiving a request, Spring reads the HTTP Method used and, depending on the resource type, calls the appropriate method defined in our interface, if present, or returns an HTTP status 405 (Method Not Allowed) otherwise.
With reference to the code above, when Spring receives a DELETE request, it executes our deleteById method.
3. Restricting Which HTTP Methods Are Exposed
Let’s imagine we have a user management system. We might, then, have a UserRepository.
And, since we are using Spring Data REST, we get a lot from having it extend CrudRepository:
@RepositoryRestResource(collectionResourceRel = "users", path = "users") public interface UserRepository extends CrudRepository<WebsiteUser, Long> {}
All our resources are exposed using the default CRUD pattern, so issuing the following command:
curl -v -X DELETE http://localhost:8080/users/<existing_user_id>
will return an HTTP status 204 (No Content returned) to confirm the deletion.
Now, let’s assume we want to hide the delete method from third parties while being able to use it internally.
We can then first add the deleteById method signature into our interface, which signals to Spring Data REST that we are going to configure it.
Then, we can use the annotation @RestResource(exported = false), which will configure Spring to skip this method when triggering the HTTP method exposure:
@Override @RestResource(exported = false) void deleteById(Long aLong);
Now, if we repeat the same cUrl command shown above, we’ll receive an HTTP Status 405 (Method Not Allowed) instead.
4. Customizing Supported HTTP Methods
The @RestResource annotation also gives us the ability to customize the URL path mapped to a repository method and the link id in the JSON returned by the HATEOAS resource discovery.
To do that, we use the optional parameters of the annotation:
- path for the URL path
- rel for the link id
Let’s go back to our UserRepository and add a simple findByEmail method:
WebsiteUser findByEmail(@Param("email") String email);
By executing a cUrl to http://localhost:8080/users/search/, we can now see our new method listed with other resources:
{ "_links": { "findByEmail": { "href": "http://localhost:8080/users/search/findByEmail{?email}" }, "self": { "href": "http://localhost:8080/users/search/" } } }
If we don’t like the default path, instead of changing the repository method, we can simply add the @RestResource annotation:
@RestResource(path = "byEmail", rel = "customFindMethod") WebsiteUser findByEmail(@Param("email") String email);
And if we do the resource discovery again, the resulting JSON will confirm our changes:
{ "_links": { "customFindMethod": { "href": "http://localhost:8080/users/search/byEmail{?email}", "templated": true }, "self": { "href": "http://localhost:8080/users/search/" } } }
5. Programmatic Configuration
Sometimes we need a finer-grained level of configuration to expose or restrict access to our HTTP methods. For example, POST on collection resources, as well as PUT and PATCH on item resources, all use the same save method.
Starting from Spring Data REST 3.1, and available with Spring Boot 2.1, we can change the exposure of a specific HTTP method through the ExposureConfiguration class. This particular configuration class exposes a lambda-based API to define both global and type-based rules.
For example, we can use ExposureConfiguration to restrict PATCH requests against the UserRepository:
public class RestConfig implements RepositoryRestConfigurer { @Override public void configureRepositoryRestConfiguration(RepositoryRestConfiguration restConfig) { ExposureConfiguration config = restConfig.getExposureConfiguration(); config.forDomainType(WebsiteUser.class).withItemExposure((metadata, httpMethods) -> httpMethods.disable(HttpMethod.PATCH)); } }
6. Conclusion
In this article, we explored how we can configure Spring Data REST to customize the HTTP methods supported by default in our resources.
As usual, the examples used in this article can be found in our GitHub project.