Book Image

Play Framework essentials

By : Julien Richard-Foy
Book Image

Play Framework essentials

By: Julien Richard-Foy

Overview of this book

This book targets Java and Scala developers who already have some experience in web development and who want to master Play framework quickly and efficiently. This book assumes you have a good level of knowledge and understanding of efficient Java and Scala code.
Table of Contents (9 chapters)
8
Index

Play – a framework used to write web applications

Play is a framework used to write web applications. As shown in the following diagram, a web application is based on a client-server architecture and uses the HTTP protocol for communication:

Play – a framework used to write web applications

Web-oriented architecture

Users have the role of clients and make HTTP requests to servers to interact with the application. The servers process their requests and send them a response. Along the way, the web application might need to make use of various databases or perhaps other web services. This entire process is depicted in the following diagram:

Play – a framework used to write web applications

The Play framework's overall architecture

This book will show you how Play can help you to write such web applications. The preceding diagram shows a first big picture of the framework's overall architecture. We will refine this picture as we read through this book, but for now it is a good start. The diagram shows a web client and a Play application. This one is made of a business layer (on the right), which provides the services and resources specific to the application. These features are exposed to the HTTP world by actions, which themselves can be logically grouped within controllers. Gray boxes represent the parts of code written by the developer (you!), while the white box (the router) represents a component already provided by Play.

HTTP requests performed by the client (1) are processed by the router that calls the corresponding action (2) according to URL patterns you configured. Actions fill the gap between the HTTP world and the domain of your application. Each action maps a service or resource of the business layer (3) to an HTTP endpoint.

All the code examples in this book will be based on a hypothetical shopping application allowing users to manage and sell their items. The service layer of this application is defined by the following Shop trait:

case class Item(id: Long, name: String, price: Double)

trait Shop {
  def list(): Seq[Item]
  def create(name: String, price: Double): Option[Item]
  def get(id: Long): Option[Item]
  def update(id: Long, name: String, price: Double): Option[Item]
  def delete(id: Long): Boolean
}

In Java, the service layer is defined by the following Shop interface:

public class Item {

  public final Long id;
  public final String name;
  public final Double price;

  public Item(Long id, String name, Double price) {
    this.id = id;
    this.name = name;
    this.price = price;
  }

}

interface Shop {
  List<Item> list();
  Item create(String name, Double price);
  Item get(Long id);
  Item update(Long id, String name, Double price);
  Boolean delete(Long id);
}

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

The Item type simply says that an item has a name, a price, and an ID. The Shop type defines the typical Create, Read, Update, and Delete (CRUD) operations we want to do. Connecting with the figure that shows the architecture of Play applications, these types represent the business layer of your web service and their definition should live in a models package in the app/ source directory. The remainder of this chapter explains how to write a controller exposing this business layer via HTTP endpoints using JSON to represent the data.

As an example, here is a possible minimalist Scala implementation of the Shop trait:

package models

import scala.collection.concurrent.TrieMap
import java.util.concurrent.atomic.AtomicLong

object Shop extends Shop {
  private val items = TrieMap.empty[Long, Item]
  private val seq = new AtomicLong

  def list(): Seq[Item] = items.values.to[Seq]

  def create(name: String, price: Double): Option[Item] = {
    val id = seq.incrementAndGet()
    val item = Item(id, name, price)
    items.put(id, item)
    Some(item)
  }

  def get(id: Long): Option[Item] = items.get(id)

  def update(id: Long, name: String, price: Double): Option[Item] = {
    val item = Item(id, name, price)
    items.replace(id, item)
    Some(item)
  }

  def delete(id: Long): Boolean = items.remove(id).isDefined
}

This implementation stores the data in memory, so it loses everything each time the application restarts! Nevertheless, it is a sufficient business layer basis, letting us focus on the web layer. The implementation uses a concurrent collection to solve concurrency issues. Indeed, as I will explain later, the code called by the controllers must be thread safe.

For Java developers, here is a minimalist implementation of the Shop interface:

import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicLong;

new Shop() {

  SortedMap<Long, Item> items = new ConcurrentSkipListMap<>();
  AtomicLong seq = new AtomicLong();

  @Override
  public Collection<Item> list() {
    return new ArrayList<>(items.values());
  }
  @Override
  public Item create(String name, Double price) {
    Long id = seq.incrementAndGet();
    Item item = new Item(id, name, price);
    items.put(id, item);
    return item;
  }

  @Override
  public Item get(Long id) {
    return items.get(id);
  }

  @Override
  public synchronized Item update(Long id, String name, Double price) {
    Item item = items.get(id);
    if (item != null) {
      Item updated = new Item(id, name, price);
      items.put(id, updated);
      return updated;
    } else return null;
  }

  @Override
  public Boolean delete(Long id) {
    return items.remove(id) != null;
  }
};

As previously mentioned, the code called by controllers must be thread safe, hence the use of Java concurrent collections.