REST API using Play Framework with Java

REST API using Play Framework with Java

Introduction

         In the latest Play 2.6 release, they have decided not to support Activator. I was searching online for a basic application in the latest Play 2.6 release. But I could not find any post or tutorial. Hence I decided to come up with this post.  In this post, we will be creating an Application using Play Framework in Java with GET, POST, PUT and DELETE APIs for CRUD operations on an Employee Entity class. To keep things simple, all data will be kept in memory in a simple map. Play as a framework does support UI as well, however in this tutorial we will be focusing only on the services part and not the UI.

Play Framework        

        Play Framework is built on Akka and is based on a lightweight, stateless, web-friendly architecture. Play provides predictable and minimal resource consumption (CPU, memory, threads) for highly-scalable applications. It is reactive and provides non blocking I/O operations.

For more details on Play Framework, you can check: Play Framework Website.

Requirements to Run the Application:

1. Intellij IDE with SBT Plugin

In this tutorial I will help you to build REST APIs using Play Framework with Java in a few simple steps.

Step 1: Create a new application using Play starter project

Download a Java Starter example from: Play Starter Projects Site
I downloaded, Play Starter Java Example as a zip file and extracted it. After extracting, to create the folder structure for a new application, open the folder in command prompt and execute the command: sbt new playframework/play-java-seed.g8 
D:\Learning\play-java-starter-example>sbt new playframework/play-java-seed.g8
At the end of this execution, it prompts you to enter the name, organization, scala version and play version of the new project.
I have used:
name: PlayREST
organization: com.aj
scala_version: 2.12.2
play_version: 2.6.5
This will create the folder structure of the new project in the same location of execution.
As we are focusing on the REST APIs and not the UI, only the following folders and file are required from the generated folder structure:
Folder:
  • app
  • conf
  • project
File:
  • build.sbt

Step 2: Dependencies in build.sbt

The file build.sbt will be generated as part of Step 1. Here is the full build.sbt:
name := """PlayREST"""
organization := "com.aj"

version := "1.0"

lazy val root = (project in file(".")).enablePlugins(PlayJava)

scalaVersion := "2.12.2"

libraryDependencies += guice

Step 3: Create the Entity class

In this post, I am using a simple entity Employee with attributes: ID, NAME, DEPARTMENT and SALARY. Here is the Entity Class, Employee.java:
package entities;

public class Employee {

    private int id;
    private String name;
    private String department;
    private int salary;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", department='" + department + '\'' +
                ", salary=" + salary +
                '}';
    }
}

Step 4: Create the Service Class

Service class creates a HashMap to keep all the employee data in memory. It also has implementations for the following operations:
  1. Create an Employee
  2. Get/Read an Employee
  3. Get All/Read All Employees
  4. Update an Employee
  5. Delete an Employee 
Here is the code for EmployeeService.java:
package services;

import entities.Employee;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class EmployeeService {
    private static EmployeeService instance;
    private Map<Integer, Employee> employees = new HashMap<>();

    public static EmployeeService getInstance() {
        if (instance == null) {
            instance = new EmployeeService();
        }
        return instance;
    }

    public Employee addEmployee(Employee employee) {
        int id = employees.size()+1;
        employee.setId(id);
        employees.put(id, employee);
        return employee;
    }

    public Employee getEmployee(int id) {
        return employees.get(id);
    }

    public Set<Employee> getAllEmployees() {
        return new HashSet<>(employees.values());
    }

    public Employee updateEmployee(Employee employee) {
        int id = employee.getId();
        if (employees.containsKey(id)) {
            employees.put(id, employee);
            return employee;
        }
        return null;
    }

    public boolean deleteEmployee(int id) {
        return employees.remove(id) != null;
    }
}

Step 5: Create a Method to handle the response of all the APIs in a Util Class 

Here is the code for ApplicationUtil.java:
package utils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import play.libs.Json;

public class ApplicationUtil {

    public static ObjectNode createResponse(Object response, boolean ok) {
        ObjectNode result = Json.newObject();
        result.put("status", ok);
        if (response instanceof String)
            result.put("response", (String) response);
        else result.set("response", (JsonNode) response);

        return result;
    }
}

Step 6: Create Controller Class with RESTful APIs for CRUD operations on Employee Entity

The EmployeeController class has the following APIs:
  1. GET API to get employee by ID.
  2. GET API to get all employees.
  3. POST API to create an employee.
  4. PUT API to update an employee.
  5. DELETE API to delete an employee by ID
In this class you can observe how I am using Logger in the application.
Here is the code for EmployeeController.java:
package controllers;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import entities.Employee;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;
import services.EmployeeService;
import utils.ApplicationUtil;

import java.util.Set;

public class EmployeeController extends Controller {

    private static final Logger logger = LoggerFactory.getLogger("controller");

    public Result create() {
        JsonNode json = request().body().asJson();
        if (json == null) {
            return badRequest(ApplicationUtil.createResponse("Expecting JSON data", false));
        }
        logger.debug("In EmployeeController.create(), input is: {}", json.toString());
        Employee employee = EmployeeService.getInstance().addEmployee(Json.fromJson(json, Employee.class));
        JsonNode jsonObject = Json.toJson(employee);
        return created(ApplicationUtil.createResponse(jsonObject, true));
    }

    public Result update() {
        logger.debug("In EmployeeController.update()");
        JsonNode json = request().body().asJson();
        if (json == null) {
            return badRequest(ApplicationUtil.createResponse("Expecting Json data", false));
        }
        Employee employee = EmployeeService.getInstance().updateEmployee(Json.fromJson(json, Employee.class));
        logger.debug("In EmployeeController.update(), employee is: {}",employee);
        if (employee == null) {
            return notFound(ApplicationUtil.createResponse("Employee not found", false));
        }

        JsonNode jsonObject = Json.toJson(employee);
        return ok(ApplicationUtil.createResponse(jsonObject, true));
    }

    public Result retrieve(int id) {
        logger.debug("In EmployeeController.retrieve(), retrieve employee with id: {}",id);
        if (EmployeeService.getInstance().getEmployee(id) == null) {
            return notFound(ApplicationUtil.createResponse("Employee with id:" + id + " not found", false));
        }
        JsonNode jsonObjects = Json.toJson(EmployeeService.getInstance().getEmployee(id));
        logger.debug("In EmployeeController.retrieve(), result is: {}",jsonObjects.toString());
        return ok(ApplicationUtil.createResponse(jsonObjects, true));
    }

    public Result listEmployees() {
        Set<Employee> result = EmployeeService.getInstance().getAllEmployees();
        logger.debug("In EmployeeController.listEmployees(), result is: {}",result.toString());
        ObjectMapper mapper = new ObjectMapper();

        JsonNode jsonData = mapper.convertValue(result, JsonNode.class);
        return ok(ApplicationUtil.createResponse(jsonData, true));

    }

    public Result delete(int id) {
        logger.debug("In EmployeeController.retrieve(), delete employee with id: {}",id);
        if (!EmployeeService.getInstance().deleteEmployee(id)) {
            return notFound(ApplicationUtil.createResponse("Employee with id:" + id + " not found", false));
        }
        return ok(ApplicationUtil.createResponse("Employee with id:" + id + " deleted", true));
    }
}

Step 7: routes

One of the most important files in the Play application is the file: routes. This file defines all application routes (APIs) and their corresponding implementations. Here is the file routes:
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# APIs in EmployeeController
GET     /employee              controllers.EmployeeController.listEmployees()
GET     /employee/:id          controllers.EmployeeController.retrieve(id:Int)
POST    /employee              controllers.EmployeeController.create()
PUT     /employee              controllers.EmployeeController.update()
DELETE  /employee/:id          controllers.EmployeeController.delete(id:Int)

# Map static resources from the /public folder to the /assets URL path
GET     /assets/*file               controllers.Assets.versioned(path="/public", file: Asset)

Run Application:

1. To run application in Intellij IDE create a new SBT Task using the following:
    Tasks: run
    Since we are running a light application, I have modified the VM parameters by reducing the -Xms and -Xmx parameters
    VM parameters: -Xms256M -Xmx512M -Xss1M -XX:+CMSClassUnloadingEnabled

2. To run the application from Command Prompt:
    Download SBT from SBT download page and install the SBT launcher on your system, which provides the sbt command.
    Run the application using the following commands:
$ cd PlayREST
$ sbt

[PlayREST] $ run

API calls and results:

The application runs on the default port 9000.
1. POST API to create an employee
    JSON Request Body:
{
 "name": "Jane",
 "department": "Technology",
 "salary" : 15000
}
2. GET API to get employee by ID
    http://localhost:9000/employee/1

3. GET API to get all employees
    http://localhost:9000/employee

4. PUT  API to update an employee
    http://localhost:9000/employee
    JSON Request Body:
{
 "id": 1,
 "name": "Jane",
 "department": "Technology",
 "salary": 20000
} 
5. DELETE API to delete an employee by ID
    http://localhost:9000/employee/1

Conclusion and GitHub link:

    In this post I have shown you how you can create an application in the latest Play 2.6 Release, build REST APIs and perform CRUD operations. The code used in this post is available on GitHub.
    Learn the most popular and trending technologies like Machine Learning, Angular 5, Internet of Things (IoT), Akka HTTP, Play Framework, Dropwizard, Docker, Elastic Stack, Netflix Eureka, Netflix Zuul, Spring Cloud, Spring Boot, Flask and RESTful Web Service integration with MongoDB, Kafka, Redis, Aerospike, MySQL DB in simple steps by reading my most popular blog posts at Software Developer Central.
    If you like my post, please feel free to share it using the share button just below this paragraph or next to the heading of the post. You can also tweet with #SoftwareDeveloperCentral on Twitter. To get a notification on my latest posts or to keep the conversation going, you can follow me on Twitter. Please leave a note below if you have any questions or comments.

Comments

  1. Replies
    1. Hi Mani Kannan
      The code used in this blog post is available on GitHub. All the java files are in the app folder

      Delete
  2. how can i use mongodb with play framwork 2.6 as java developer

    ReplyDelete

Post a Comment

Popular Posts

Asynchronous Processing (@Async) in Spring Boot

Elasticsearch, Logstash, Kibana Tutorial: Load MySQL Data into Elasticsearch