Creating a CRUD REST API/Service with Spark
Hello everyone, today we will discuss how to build RESTful API using Spark.
Spark is a micro web framework for Java. Spark aims for simplicity and provides only a minimal set of features. However, it provides everything needed to build a web application in a few lines of Java code. Spark is built around Java 8 Lambda Expression philosophy, making it less verbose than most applications inscribed in other Java frameworks.
Routes
Let's list the routes that make up our API:
- GET /employees — get the list of all employees
- GET /employees/:id — get employees with given id
- POST /employees/:id — add an employee
- PUT /employees/:id — edit a particular employee
- DELETE /employees/:id — delete a particular employees
Let's start to build RSETFul API with Spark
Maven Dependencies[pom.xml]
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spark_api_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spark_api_demo</name>
<description>Demo</description>
<properties>
<java.version>1.8</java.version>
<sparkjava.spark-core.version>2.5.4</sparkjava.spark-core.version>
<google.code.gson.version>2.8.0</google.code.gson.version>
</properties>
<dependencies>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>${sparkjava.spark-core.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${google.code.gson.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Model[Employee.class]
We will design a simple REST web service for the following Employee entity:
package com.knf.spark.api.demo;
class Employee {
private String id;
private String firstName;
private String lastName;
private String email;
public Employee(String id, String firstName, String lastName, String email) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Employee Service[EmployeeService.class]
EmployeeService interface declaring the CRUD operations for the Employee entity:
package com.knf.spark.api.demo;
import java.util.Collection;
public interface EmployeeService {
public void addEmployee(Employee employee);
public Collection<Employee> getEmployees();
public Employee getEmployee(String id);
public Employee editEmployee(Employee employee) throws EmployeeException;
public void deleteEmployee(String id);
public boolean employeeExist(String id);
}
EmployeeServiceImpl.class
package com.knf.spark.api.demo;
import java.util.Collection;
import java.util.HashMap;
public class EmployeeServiceImpl implements EmployeeService {
private HashMap<String, Employee> employeeMap;
public EmployeeServiceImpl() {
employeeMap = new HashMap<>();
}
@Override
public void addEmployee(Employee emp) {
employeeMap.put(emp.getId(), emp);
}
@Override
public Collection<Employee> getEmployees() {
return employeeMap.values();
}
@Override
public Employee getEmployee(String id) {
return employeeMap.get(id);
}
@Override
public Employee editEmployee(Employee forEdit) throws EmployeeException {
try {
if (forEdit.getId() == null)
throw new EmployeeException("ID cannot be blank");
Employee toEdit = employeeMap.get(forEdit.getId());
if (toEdit == null)
throw new EmployeeException("Employee not found");
if (forEdit.getEmail() != null) {
toEdit.setEmail(forEdit.getEmail());
}
if (forEdit.getFirstName() != null) {
toEdit.setFirstName(forEdit.getFirstName());
}
if (forEdit.getLastName() != null) {
toEdit.setLastName(forEdit.getLastName());
}
if (forEdit.getId() != null) {
toEdit.setId(forEdit.getId());
}
return toEdit;
} catch (Exception ex) {
throw new EmployeeException(ex.getMessage());
}
}
@Override
public void deleteEmployee(String id) {
employeeMap.remove(id);
}
@Override
public boolean employeeExist(String id) {
return employeeMap.containsKey(id);
}
}
StandardResponse.class
package com.knf.spark.api.demo;
import com.google.gson.JsonElement;
public class StandardResponse {
private StatusResponse status;
private String message;
private JsonElement data;
public StandardResponse(StatusResponse status) {
this.status = status;
}
public StandardResponse(StatusResponse status, String message) {
this.status = status;
this.message = message;
}
public StandardResponse(StatusResponse status, JsonElement data) {
this.status = status;
this.data = data;
}
public StatusResponse getStatus() {
return status;
}
public void setStatus(StatusResponse status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public JsonElement getData() {
return data;
}
public void setData(JsonElement data) {
this.data = data;
}
}
StatusResponse.class
package com.knf.spark.api.demo;
public enum StatusResponse {
SUCCESS("Success"), ERROR("Error");
final private String status;
StatusResponse(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
}
Controller[SparkRestController.class]
package com.knf.spark.api.demo;
import static spark.Spark.delete;
import static spark.Spark.get;
import static spark.Spark.post;
import static spark.Spark.put;
import com.google.gson.Gson;
public class SparkRestController {
public static void main(String[] args) {
final EmployeeService employeeService = new EmployeeServiceImpl();
post("/employees", (request, response) -> {
response.type("application/json");
Employee employee = new Gson().fromJson
(request.body(), Employee.class);
employeeService.addEmployee(employee);
return new Gson().toJson(new StandardResponse
(StatusResponse.SUCCESS));
});
get("/employees", (request, response) -> {
response.type("application/json");
return new Gson().toJson(new StandardResponse
(StatusResponse.SUCCESS,
new Gson().toJsonTree(employeeService.getEmployees())));
});
get("/employees/:id", (request, response) -> {
response.type("application/json");
return new Gson().toJson(new StandardResponse
(StatusResponse.SUCCESS,
new Gson().toJsonTree(employeeService.getEmployee
(request.params(":id")))));
});
put("/employees/:id", (request, response) -> {
response.type("application/json");
Employee toEdit = new Gson().fromJson(request.body(),
Employee.class);
Employee editedEmployee = employeeService.editEmployee(toEdit);
if (editedEmployee != null) {
return new Gson()
.toJson(new StandardResponse
(StatusResponse.SUCCESS, new Gson().
toJsonTree(editedEmployee)));
} else {
return new Gson().toJson(new StandardResponse
(StatusResponse.ERROR,
new Gson().toJson
("Employee not found or error in edit")));
}
});
delete("/employees/:id", (request, response) -> {
response.type("application/json");
employeeService.deleteEmployee(request.params(":id"));
return new Gson().toJson(new StandardResponse
(StatusResponse.SUCCESS, "employee deleted successfully"));
});
}
}
Testing the 'Employee' API using postman
After running the class SparkRestController as a normal Java class, you will be able to access the service on its default port of 4567.
1. Add Employee:
2. Get Employee by Id:
3. Fetch all Employee
4. Update Employee
5. Delete Employee
Download source code
git clone: