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: 

  1. GET /employees — get the list of all employees 
  2. GET /employees/:id — get employees with given id 
  3. POST /employees/:id — add an employee
  4. PUT /employees/:id — edit a particular employee 
  5. 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: 

Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Java, Spring Boot Mini Project - Library Management System - Download

ReactJS, Spring Boot JWT Authentication Example

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete