Play 2[Scala], React.js,GraphQL- Part 1

Dipro Chowdhury
9 min readOct 8, 2019

--

Photo Credit: mediocozz

Hi folks, it’s another day in this never ending journey in the dev world. Today I will be working on a small demo on how React.js, GraphQL and Play 2 Framework can be used together to create a very basic working application that you can extend to a fully featured reactive application if you want.

Let’s get started…

If you are a Java/Scala person, then Play 2 framework can be a good choice for building a scalable web application. In this tutorial, I will be using Play 2 Framework using Scala programming language to build a t-shirt store app. I will be using some Mock values instead of setting up a database for making it as simple as possible.

There are some required tools we need to install before we start using play 2 framework. Either sbt or gradle can be used as build tool. I will be using sbt for this demo. For more details you can follow this link.

Assuming sbt is already installed, we can create a new play 2 scala app by running the following command in the terminal

sbt new playframework/play-scala-seed.g8

You should be in this step after running the above command and you can define the app name in terminal

Creating New App in Play2 Framework

Now a folder called tshirtstoreapp should be created where ever you created the project.

Any IDE can be used to work on this play project, but mostly used IDE for managing Play2 framework is Eclipse and IntelliJ. I am going to use IntelliJ IDE [Ultimate Edition] for this project.

Using IntelliJ, we can open this app by clicking import project button on the home screen.

IntelliJ Home Screen

Click yes and then click finish to open the app in IntelliJ IDE.

Once you open the app in IntelliJ IDE, you will see this screen below

The directories are structured according to the MVC architectural pattern.You can get more information on the anatomy of the play application here.

There are multiple ways to run this app. One of the easiest ways is to navigate to the sbt shell and typing run command.

Now if you open any browser and go to http://localhost:9000, you should the the following screen.

If you navigate to the routes file under conf folder, you will see some predefined routes are already there. Let’s create our tshirt model first.

Let’s say a tshirt will have an id, color, picture(url), and price.

To stop the running process you can click on the red stop button on the bottom-left tool bar.

Create a package called models inside the app folder.

Then create a scala class called Tshirt inside the models package.

Create a new Scala Class

Lets use singleton pattern for this demo. Unlike Java, primary constructor in a scala class share the same body of the class except any declared methods. So the syntax for declaring constructor is as follows:

class class_name(parameter_list){
/** statements */
}

For our Tshirt class, for id, color, picture and price attributes, we will have the following code:

class Tshirt(var id: Int = 0, var color: String = "", var pic_url: String = "", var price: Int = 0) {

}

For keeping it as simple as possible, we will not setup any database for this demo. Since we defined some default value for the arguments, we can create new instance of Tshirt class without passing any arguments.

Lets create a new Set that will hold all our tshirt data.

var tShirts: Set[Tshirt] = Set()

Now lets create an add method that can be used to add new Tshirt object to this Set.

def add(tshirt: Tshirt): Unit ={
tShirts+=tshirt
}

Just in case if you are wondering, Unit is analogous to a Java method which is declared void. So this is a void method called add that takes an argument called tshirt of type Tshirt and that this object to the tShirts Set defined above.

Lets create a getter method for the tShirts Set

def getTshirts(): Set[Tshirt] ={
return tShirts
}

In Java we can have a private method that can be returning a instance of that class. In Scala it will be a bit different since we are not allowed to create static methods in a scala class. In Scala same purpose can be fulfilled using object class. You can get more information about object class here.

Now, add an Object class outside the Tshirt class as follows. [Same file or separate file, it’s the same file just to make it simpler]

// singleton object
object Tshirt {
var tshirts = new Tshirt()
tshirts.add(new Tshirt(1, "red", "https://live.staticflickr.com/5246/5276588069_ce5ab13b09.jpg", 20))
tshirts.add(new Tshirt(2, "yellow", "https://live.staticflickr.com/654/21474568892_0369bd9f43.jpg", 25))
tshirts.add(new Tshirt(3, "blue", "https://live.staticflickr.com/8086/8454636463_8ff5034d2d.jpg", 30))

def getAllTshirts(): Set[Tshirt] ={
return tshirts.getTshirts()
}
}

Above object class is responsible to create a new instance of the Tshirt class and add 3 differrent Objects of type Tshirt into the tShirts Set.

It also has a method that can be called to get a Set of Tshirt objects for this instance.

Your Tshirt.scala file should look like this now.

package models

class Tshirt(var id: Int, var color: String, var pic_url: String, var price: Int) {

var tShirts: Set[Tshirt] = Set()

def add(tshirt: Tshirt): Unit ={
tShirts+=tshirt
}

def getTshirts(): Set[Tshirt] ={
return tShirts
}


}

// singleton object
object Tshirt {
var tshirts = new Tshirt()
tshirts.add(new Tshirt(1, "red", "https://live.staticflickr.com/5246/5276588069_ce5ab13b09.jpg", 20))
tshirts.add(new Tshirt(2, "yellow", "https://live.staticflickr.com/654/21474568892_0369bd9f43.jpg", 25))
tshirts.add(new Tshirt(3, "blue", "https://live.staticflickr.com/8086/8454636463_8ff5034d2d.jpg", 30))

def getAllTshirts(): Set[Tshirt] ={
return tshirts.getTshirts()
}
}

At this point, we can quickly test this code by creating a new route and a REST endpoint that will return Json data of what we have in the tShirts SET.

Let’s create a controller in the controllers folder called TshirtController.

Add the following code inside TshirtController file.

package controllers

import javax.inject._
import models.Tshirt
import play.api.libs.json.{JsObject, Json}
import play.api.mvc._

import scala.collection.mutable.ListBuffer

/**
* This controller creates an `Action
` to handle HTTP requests to the
* application's home page.
*/
@Singleton
class TshirtController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {

// return All books
def index() = Action { implicit request: Request[AnyContent] =>
val tshirts = Tshirt.getAllTshirts() // Calling getAllTshirts method on singleton object
var tshirtList = new ListBuffer[JsObject]()
for(tshirt <- tshirts){
val js = Json.obj("id" -> tshirt.id, "color" -> tshirt.color, "url" -> tshirt.pic_url, "price" -> tshirt.price)
tshirtList += js
}
Ok(Json.toJson(tshirtList.toList))
}
}

The above code is creating a new instance of Tshirt class using the object class and adding new objects and calling getAllTshirts on that object. Then we are creating a mutable list(ListBuffer) that holds objects of type JsObject.

After that we are iterating over the tshirts Set and for each tshirt, we are creating a JsObject and appending it to the ListBuffer. When done, we simply convert that ListBuffer to a List and then converting it to a Json object before returning.

Now, if we run the app and test the the endpoint [http://localhost:9000/tshirts] using curl or postman we will see a Json Object as response!

Json Response [Play 2 Framework]

Now that we know the app is working fine, we can start working on the graphql endpoint.

First remove scalaVersion := “2.13.0” in built.sbt file to avoid conflicts.

To enable graphql feature in the app, we will use a library called Sangria.

Add the following dependency in built.sbt in the the root level of the app

libraryDependencies += “org.sangria-graphql” %% “sangria” % “1.4.2”

Then create a file called SchemaDefinition.scala inside models package.

We will define GraphQL Schema using ObjectType from sangria’s schema package. Steps on how to create a GraphQL schema using sangria is very well explained in the documentation here.

First we need to import packages in SchemaDefinition.scala the mentioned below:

import sangria.schema.ObjectType
import sangria.schema.{Field, _}

Now Lets define our ObjectType

/**
* Defines a GraphQL schema for the current project
*/
object SchemaDefinition {

val Tshirt = ObjectType(
"Tshirt",
fields[Unit, Tshirt](
Field("id", IntType, resolve = _.value.id),
Field("color", StringType, resolve = _.value.color),
Field("pic_url", StringType, resolve = _.value.pic_url),
Field("price", IntType, resolve = _.value.price)
)
)
}

Let’s also define a GraphQL Query that will return a List of tshirts.

Inside SchemaDefinition object, define the Query below

val Query = ObjectType(
"Query", fields[Tshirt, Unit](
Field("tshirts", ListType(Tshirt),
description = Some("Returns a list of all available books."),
resolve = _.ctx.getTshirts())
))

Since this query needs to return a List of tshirt objects, we need a method that will convert Set of tshirts to a List of Tshirts. Add the following method in the Tshirt.scala file.

def getAll(): List[Tshirt] ={
return Tshirt.getAllTshirts().toList
}

Finally we can make this Schema available for any GraphQL clients. Add the following code at the end of SchemaDefinition.scala file.

val TshirtSchema = Schema(Query)

We can quickly create an endpoint that will return a description of this GraphQL Query and Object we just created.

add the following code in your routes file under conf folder.

# Render GraphQl Schema
GET /render-schema controllers.TshirtController.renderSchema()

And then we need a method in our controller to render this Schema using SchemaRenderer from sangria’s renderer package. Add the following code in TshirtController file.

def renderSchema = Action {
Ok(SchemaRenderer.renderSchema(SchemaDefinition.TshirtSchema))
}

Now if we run the app and make a get request at http://localhost:9000/render-schema

We should see details about our GraphQL query and object that we just created.

Insomnia HTTP Client

In order to create a GraphQL endpoint, that will work with sangria, we need to add dependency to our project.

add the following dependency library in built.sbt file

libraryDependencies += "org.sangria-graphql" %% "sangria-play-json" % "1.0.5"

Now add the following code in TshirtController.scala file

// GraphQl Query Handler
def graphql = Action.async(parse.json) { request =>
val query = (request.body \ "query").as[String]

QueryParser.parse(query) match {
// query parsed successfully, time to execute it!
case Success(queryAst) ⇒
executeGraphQLQuery(queryAst)

// can't parse GraphQL query, return error
case Failure(error: SyntaxError) ⇒
Future.successful(BadRequest(Json.obj("error" → error.getMessage)))
}
}

Import all the necessary packages. The above code is taken from this example.

But it’s a modified version since in our demo, we only have a simple query without any arguments, so no need to have extra code for parsing variables.

At this point, the code should throw errors since we don’t have executeGraphQLQuery method in out file yet.

Add the following method in TshirtController file

def executeGraphQLQuery(query: Document) =
Executor.execute(SchemaDefinition.TshirtSchema, query, new Tshirt())
.map(Ok(_))
.recover {
case error: QueryAnalysisError ⇒ BadRequest(error.resolveError)
case error: ErrorWithResolver ⇒ InternalServerError(error.resolveError)
}

Above method will return a Future of Type result, which scala way of performing concurrent operation, we need to import actor system from akka package. In TshirtController file, replace

class TshirtController  @Inject()(cc: ControllerComponents) extends AbstractController(cc) {

with

class TshirtController @Inject()(system: ActorSystem, config: Configuration) extends InjectedController {
import system.dispatcher

Finally, add a graphql route in routes file under conf folder

# Get all Tshirts, GraphQl Endpoint
POST /graphql controllers.TshirtController.graphql

That’s it, a very basic we have created a very basic play 2 application with a simple graphql endpoint that returns some mock data when queried.

Run the application using

sbt clean compile

and then

sbt run

application should be running on localhost:9000

play running on http://localhost:9000

We can use insomia client to test this graphql endpoint

Making a graphql query in insomnia

So we have a basic backend application that is exposing a graphql endpoint with a json response. In the next demo, we will work on a React app with Apollo client that will consume this endpoint and render the data on web page.

Here’s the full code for this tutorial

Code Link

--

--