The purpose of Restzilla is to dynamically generate REST endpoints for entity CRUD. In contrast to Spring DATA REST, Restzilla follows the Controller-Service-Repository architectural pattern. Restzilla is build on convention over configuration, resulting in very minimal amounts of code with optimal functionality. It is also possible to overwrite functionality in each architectural layer.
- Generates (CRUD) REST endpoints, requiring only a JPA entity class
- Overwrite posibilities on each layer: Controller, Service, Repository
- Custom finder queries
- Swagger support
Add the Maven dependency:
<dependency>
<groupId>nl.42.restzilla</groupId>
<artifactId>restzilla</artifactId>
<version>2.0.0</version>
</dependency>
Required dependencies:
- Spring MVC (5.1+)
- Spring Data JPA (2.1+)
- Jackson (2.9+)
- Java (1.8+)
Annotate your Spring Configuration with @EnableRest
:
@EnableWebMvc
@EnableRest(basePackageClass = WebMvcConfig.class)
public class WebMvcConfig extends WebMvcConfigurerAdapter {
}
Then annotate the entities that should have REST endpoints with @RestResource
:
@Entity
@RestResource
public class User {
@Id
private Long id;
private String name;
}
That's it! Restzilla will now automatically inject a repository, service and controller. Where the controller will handle the following requests:
GET /user
GET /user/{id}
POST /user
PUT /user/{id}
DELETE /user/{id}
The GET requests by default return a collection of entities. But it is also possible to retrieve the entities as page:
GET /user?page=0&size=10
Also, the entities can be retrieved with a specific order:
GET /user?page=0&size=10&sort=id,[asc|desc]
GET /user?sort=id,[asc|desc]
You can also specify default orders per entity, as fallback when no orders are specified in the request:
@Entity
@RestResource
@SortingDefault("name")
public class User {
@Id
private Long id;
private String name;
}
More complicated orders are also possible:
@Entity
@RestResource
@SortingDefaults({
@SortingDefault("name"),
@SortingDefault(value = "id", direction = Direction.DESC)
})
public class User {
@Id
private Long id;
private String name;
}
Restzilla provides native support for "patch" requests, where you only update a fragment of the entity. For example, if we have a model with multiple properties:
@Entity
@RestResource
public class User {
@Id
private Long id;
private String name;
private String email;
}
And in our request we only want to update the name:
{
"name": "New name"
}
Our original email remains unchanged, where normally it would have been reset to null. When you do want to clear the email adress, just provide it in the body:
{
"name": "New name",
"email":
}
Sometimes you want to return the entity in a different format. For example, return a user without it's password for security reasons. Also, in some cases the create/update request bodies vary from the entity. Custom types are specified as follows:
@Entity
@RestResource(
create = @RestConfig(inputType = CreateUserForm.class, resultType = CreateUserResult.class)
)
public class User {
@Id
private Long id;
private String name;
}
With the following plain old java object:
public class CreateUserForm {
public String name;
}
Create request bodies will now be unmarshalled into a CreateUserForm object. The form is mapped to a User entity and persisted in the database. After persistence our entity is mapped to the result type and placed in the response body.
Mapping between beans is automatically handled by the BeanMapper dependency.
It's also possible to secure the endpoints, making them only accessable to certain roles:
@Entity
@RestResource(
create = @RestConfig(secured = "hasRole('ROLE_ADMIN')")
)
public class User {
@Id
private Long id;
private String name;
}
When the user does not have any of the roles we will throw a SecurityException. Note that Spring Security must be on the classpath for this functionality to work.
Logic can be customized on each of the architectural layers: Repository, Service and Controller. This is particulary handy when domain specific functionality is desired.
Restzilla relies heavily on Spring Data JPA. Each Spring Data repository will automatically be detected and used:
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findAllByActive(boolean active);
}
With the @RestQuery annotation it is also possible to configure custom finder queries. Whenever a GET request matches our specified parameters, the call will be delegated to the selected method in our repository or service bean. Paging and sorting is also supported by default, whenever the target method has a Sort or Pageable parameter type. Also, when a result type is specified the resulting array or page will automatically be mapped to that type.
@Entity
@RestResource(
queries = @RestQuery(
parameters = { "active", "version=1" },
method = "findAllByActive"
)
)
public class User {
@Id
private Long id;
private String name;
private boolean active;
}
To query all active users, we perform the following request:
GET /user?version=1&active=true
Whenever the query always returns a single result, it can be marked as unique. This way the result will be an object, rather than an array or page.
@RestQuery(parameters="active", method="findAllByActive", unique=true))
Services can have a custom implementation. By implementing the CrudService
interface your services will automatically be detected:
@Service
@Transactional
@Scope(proxyMode = TARGET_CLASS)
public class UserService implements CrudService<User, Long> {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
super(userRepository);
}
@Override
public UserRepository getRepository() {
return userRepository;
}
}
Or extend the template DefaultCrudService
template:
@Service
@Transactional
@Scope(proxyMode = TARGET_CLASS)
public class UserService extends DefaultCrudService<User, Long> {
@Autowired
public UserService(UserRepository userRepository) {
super(userRepository);
}
}
Every service method can be overridden for custom logic.
To customize the REST endpoint, just define a regular Spring MVC request mapping:
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping(method = POST)
public UserModel create(CreateUserModel model) {
// Implement
}
}
REST controllers can also use the @RestResource annotation to place have all endpoint logic in one class. In this case we also scan the controller class for the base path:
@RestController
@RequestMapping("/user")
@RestResource(entityType = User.class)
public class UserController {
@RequestMapping(method = POST)
public UserModel create(CreateUserModel model) {
// Implement
}
}
Swagger is also supported, allowing you to automatically generate the API documentation. To activate Swagger, just configure the provided plugin as follows:
@EnableWebMvc
@EnableSwagger
@EnableRest(basePackageClass = WebMvcConfig.class)
public class WebMvcConfig extends WebMvcConfigurerAdapter {
private SpringSwaggerConfig springSwaggerConfig;
@Autowired
public void setSpringSwaggerConfig(SpringSwaggerConfig springSwaggerConfig) {
this.springSwaggerConfig = springSwaggerConfig;
}
}