Last couple of weeks I had a chance to work with
spring data rest project. When I read the documentation I thought I pretty awesome.Because It has lot of features for REST api development.Here I will describe main features contains in spring data rest. At the end of this thread I will create simple rest api for product management.
What is Pure Restful Webservice ?
First we talk about what is restful web service. Restful web service is architectural style for request and response mapping in web service. There are different kind of HTTP request coming to API. But when it comes to REST api every url have different meaning for different HTTP request methiods.
Ex: /api/v1/student/ --- > GET
/api/v1/student/ ----> POST
/api/v1/student/ ---> PUT
And there are different response Status codes for different purposes.
Method |
Method |
200 OK |
201 Created |
202 Accepted |
203 Non-Authoritative Info |
204 No content |
205 Reset content |
206 Partial content |
|
300 Multiple choice |
301 Moved permanently |
302 Found |
303 See other |
304 Not modified |
306 (unused) |
307 Temporary redirect |
|
400 Bad request |
401 Unauthorized |
402 Payment required |
403 Forbidden |
404 Not found |
405 Method not allowed |
406 Not acceptable |
407 Proxy auth required |
408 Timeout |
409 Conflict |
410 Gone |
411 Length required |
412 Preconditions failed |
413 Request entity too large |
414 Requested URI too long |
415 Unsupported media |
416 Bad request range |
417 Expectation failed |
500 Server error |
501 Not implemented |
502 Bad gateway |
503 Service unavailable |
504 Gateway timeout |
505 Bad HTTP version |
As Example When we POST student obejct to rest API it will need to Send 204 no content status code rather than 200 status code.likewise there are standard ways to send response.If all the standard are fulfill it will become pure restful web service.
These are the core areas we are discus in this tutorial.
- Projection
- Search
- Advance Search
- Pagination & Sorting
- Spring Security
To Discuss spring data rest we used simple sales management demo. These are the entity classes. We have Product,Sale,SalesAgent
package dev.firelimez.io.domain;
import org.springframework.data.annotation.Id;
public class Product {
@Id
private String productId;
private String name;
private String price;
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
package dev.firelimez.io.domain;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.DBRef;
import java.util.List;
public class Sale {
@Id
private String salesId;
private String date;
@DBRef
private SalesAgent salesAgent;
@DBRef
private List<Product> products;
public String getSalesId() {
return salesId;
}
public void setSalesId(String salesId) {
this.salesId = salesId;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
public SalesAgent getSalesAgent() {
return salesAgent;
}
public void setSalesAgent(SalesAgent salesAgent) {
this.salesAgent = salesAgent;
}
}
package dev.firelimez.io.domain;
import org.springframework.data.annotation.Id;
import java.io.Serializable;
public class SalesAgent implements Serializable {
@Id
private String agentId;
private String name;
private String lastName;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getAgentId() {
return agentId;
}
public void setAgentId(String agentId) {
this.agentId = agentId;
}
}
So this tutorial I will use mongo database as database reference. First you have to add these dependencies to your maven project.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Spring data rest all are written using interfaces. So first thing we have to do is create repository. All the entity classes should have repository classes. As example this is the example Repository class.
package dev.firelimez.io.repo;
import dev.firelimez.io.domain.Product;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import java.util.List;
@RepositoryRestResource(collectionResourceRel = "products", path = "products")
public interface ProductRepository extends MongoRepository<Product, String> {
@RestResource(path = "names", rel = "demo1")
List<Product> findByName(@Param("name") String name);
@RestResource(path = "similar", rel = "demo")
List<Product> findByNameLike(@Param("name") String name);
@Override
@RestResource(exported = true)
void delete(String productId);
}
And Final step is start program as spring boot application.
package dev.firelimez.io;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StarterApplication {
public static void main(String[] args) {
SpringApplication.run(StarterApplication.class, args);
}
}
And next step is add
application.yml and configuration should be like this.
server:
port: 9008
spring:
data:
mongodb:
host: 127.0.0.1
port: 27017
database: sales_management
And that is your REST API is ready.
Projection
Projection is concept expose specific fields to rest api end points. As example in sales rest API how to get the sales agent details who are done the sales. In this case we can use projection. For that we have to add what are the properties we expect when we using projection.
Ex: sales expand projection return sales agent details with the sales objects.
package dev.firelimez.io.domain.projection;
import dev.firelimez.io.domain.Sale;
import org.springframework.data.rest.core.config.Projection;
import java.util.List;
@Projection(name = "expand", types = Sale.class)
interface SalesProjection {
String getSalesId();
String getDate();
SalesAgentProjection getSalesAgent();
List<ProductProjection> getProducts();
}
package dev.firelimez.io.domain.projection;
import org.springframework.beans.factory.annotation.Value;
interface SalesAgentProjection {
int getAge();
String getAgentId();
@Value("#{target.name} #{target.lastName}")
String getFullName();
}
And then you can access projection data using this way.
http://localhost:9008/sales?projection=expand
Search & Advance Search
When we creating rest api biggest issue is dealing with database and based on user REST end point what we did was write query and get result from database and return to user. But spring data rest support queryless way to get result from database.
Ex: if we want to get product by product name
@RestResource(path = "names", rel = "name")
List<Product> findByName(@Param("name") String name);
These are the inbuild
query methods in spring jpa repository.
Advanced Search
For advance search we have to use ExampleMatcher class and it will support advance search in spring data rest.
@Autowired
SalesAgentRepository salesAgentRepository;
@RequestMapping(method = RequestMethod.POST, path = "/api/v2/agent/search/advance", consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public List<SalesAgent> claimSupportTicket(@RequestBody SalesAgent salesAgent) {
ExampleMatcher exampleMatcher = ExampleMatcher.matching().withIgnoreNullValues().withIgnoreCase();
List<SalesAgent> advanceSearch = salesAgentRepository.findAll(Example.of(salesAgent, exampleMatcher));
return advanceSearch;
}