Hands-on read JSON data from any external API with Scala

Reading Time: 3 minutes

Hi folks, In this blog, we will write HTTP server + client code which calls the below external API using Scala and play framework

API data in JSON format https://jsonplaceholder.typicode.com/comments

Project Setup

We must install the SBT command-line tool (at least JDK 8). In this blog, we’re using SBT version 1.7.1 to install Play Framework version 2.8.1.

Step 1:

First, we need to add some dependencies in the build.sbt file.

libraryDependencies ++= Seq(

  ws,

  "org.scalatestplus.play" %% "scalatestplus-play" % "5.0.0" % Test,
  
  "io.spray" %% "spray-json" % "1.3.6"

)

Step 2 :

Now we create a model which handles JSON API data under the model’s package

/app/models

package models

import spray.json.DefaultJsonProtocol.{IntJsonFormat, StringJsonFormat}

import spray.json.{JsValue, RootJsonFormat}

case class APIResponse(postId: Int, id: Int, name: String, email: String, 

body: String)

object APIResponse {

  implicit object TestJsonFormat extends RootJsonFormat[APIResponse] {

    override def read(json: JsValue): APIResponse = {

      val jsObject = json.asJsObject

      val jsFields = jsObject.fields

      val postId = jsFields.get("postId").map(_.convertTo[Int]).getOrElse(0)

      val id = jsFields.get("id").map(_.convertTo[Int]).getOrElse(0)

      val name = jsFields.get("name").map(_.convertTo[String]).getOrElse("_")

      val email=jsFields.get("email").map(_.convertTo[String]).getOrElse("_")

      val body = jsFields.get("body").map(_.convertTo[String]).getOrElse("_")

      APIResponse(postId, id, name, email, body)

    }

    override def write(obj: APIResponse): JsValue = ???
  }
}

Step 3 :

Creating a Home controller file under the controllers package that works as a communicator between the model and the view

package controllers

import models.APIResponse

import javax.inject._

import spray.json._

import play.api.mvc._

import play.api.libs.ws.WSClient

import spray.json.DefaultJsonProtocol.listFormat

import scala.concurrent.ExecutionContext.Implicits.global


@Singleton

class HomeController @Inject()(

                                cc: ControllerComponents,

                                ws: WSClient,

                              ) extends AbstractController(cc) {

  def index(postId: Option[Int], id: Option[Int], name: Option[String], 

email: Option[String]): Action[AnyContent] =

    Action.async { implicit request: Request[AnyContent] =>

      val result = 

ws.url(s"https://jsonplaceholder.typicode.com/comments").get()

      result.map { response =>

        val jsValue = response.body.parseJson

        val listOfAPIResponse: List[APIResponse] = 

jsValue.convertTo[List[APIResponse]]

        if (id.isDefined) {

          val filterByID = listOfAPIResponse.filter(apiResponse => 

apiResponse.id == id.get)

          Ok(views.html.index(filterByID))

        }

        else if (postId.isDefined) {

          val filterByPostId = listOfAPIResponse.filter(apiResponse => 

apiResponse.postId == postId.get)

          Ok(views.html.index(filterByPostId))

        }

        else if (name.isDefined) {

          val filterByName = listOfAPIResponse.filter(apiResponse => 

apiResponse.name.contains(name.get))

          Ok(views.html.index(filterByName))

        }

        else if (email.isDefined) {

          val filterByEmail = listOfAPIResponse.filter(apiResponse => 

apiResponse.email.contains(email.get))

          Ok(views.html.index(filterByEmail))

        }

        else {

          Ok(views.html.index(listOfAPIResponse))

        }

      }

    }

}

Step 4 :

We finished the backend part. let’s create a simple table using HTML. so we created a view file under the views package that works as a display of the content on your browser.

@import models.APIResponse

@(apiResponse: List[APIResponse])

@main("API") {
 
 <body>

    <h1>Result : @apiResponse.length</h1>

    <table id="customers">

      <tr>

        <th>ID</th>

        <th>PostId</th>

        <th>Name</th>

        <th>Email</th>

        <th>Body</th>

      </tr>

      @for(data <- apiResponse){

        <tr>

          <td>@data.id</td>

          <td>@data.postId</td>

          <td>@data.name</td>

          <td>@data.email</td>

          <td>@data.body</td>

        </tr>

      }

    </table>

  </body>
}

Step 5 :

Now we create a route under the conf/route package

GET     /API                           

controllers.HomeController.index(postId:Option[Int] ?= None, id:Option[Int] 

?= None, name:Option[String] ?= None, email:Option[String])

Step 6 :

Done with the coding part. now we compile the project using SBT commands. run this command on your terminal

$ sbt compile run

Testing

Open your favorite browser and enter this URL http://localhost:9000/API

API data in table format

If you want to filter your table by using Id, postId, name, and email

Filter by Id

http://localhost:9000/API?id=91

Filter by postId

http://localhost:9000/API?postId=9

Filter by email

http://localhost:9000/API?email=.com

Filter by name

http://localhost:9000/API?name=reiciendis

Template link : https://techhub.knoldus.com/dashboard/projects/play/63a15b95ca01002cf3245b25

Conclusion

Through this blog, You will get the Solution of reading data from JSON API using Scala and the Play framework. We explored how to set up the play framework.

Written by 

Vineet Chauhan is a Software Consultant at Knoldus Inc. His practice area is Scala. He is a good team worker. He is always ready to face any challenging task.