Building a Low-Level REST API for a Bookstore with Akka HTTP in Scala

Vishalsingh
Codinoverse
Published in
4 min readJul 17, 2024
Rest API

In this blog, we’ll explore how to build a low-level REST API for a bookstore using Akka HTTP in Scala. Our API will cover basic CRUD operations for books, including creating new books, fetching book details, checking inventory, and updating book quantities.

What is Http?

HTTP stands for HyperText Transfer Protocol. It is the foundation for data communication on the World Wide Web. When you type a website address into your browser and hit enter, your browser sends an HTTP request to the web server hosting that website. The server processes the request and sends back an HTTP response. Your browser then interprets this response and displays it as a webpage

Incoming HTTP Request:

An incoming HTTP request from a client to a server contains important information. This includes the request method (GET, POST, PUT, etc.), the URL being requested, headers, query parameters, and the request body (if any)

HTTP Response :

An HTTP response is sent from a server back to the client in response to an HTTP request. It includes important information such as the status code (e.g., 200 for success, 404 for not found), headers, and the response body.

HTTP Request and HTTP Response are core components of web server frameworks like Akka HTTP, Node.js’s Express.js, Python’s Flask, and many others. They allow developers to handle incoming requests and send appropriate responses, enabling the implementation of web applications and APIs

Akka HTTP :

Akka HTTP is a toolkit used for creating RESTful APIs. It implements a full server and client-side HTTP stack on top of Akka Actor and Akka Stream modules. Akka HTTP offers two distinct APIs with varying levels of abstraction.

  1. Low-level
  2. High-level

Low-Level Akka HTTP API

The Akka HTTP Low-Level API involves direct manipulation of HttpRequest and HttpResponse objects, along with related classes like HttpEntity, HttpMethods, and HttpHeaders. This API allows manual creation of requests, processing of incoming requests, and construction of responses.

Example: Building an Akka HTTP Server

Let’s create a server that receives HTTP requests and sends HTTP responses.

To run Akka HTTP in your application, include the following libraries in your build.sbt file:

libraryDependencies++=Seq(
"com.typesafe.akka" %% "akka-actor-typed" % "2.6.20",
"ch.qos.logback" % "logback-classic" % "1.2.10",
"com.typesafe.akka" %% "akka-http" % "10.2.10",
"com.typesafe.akka" %% "akka-stream" % "2.6.20",
"com.typesafe.akka" %% "akka-http-spray-json" % "10.2.10",
"ch.megard" %% "akka-http-cors" % "1.2.0",
"com.typesafe.akka" %% "akka-stream-testkit" % "2.6.20",
"com.typesafe.akka" %% "akka-http-testkit" % "10.2.10",
"org.scalatest" %% "scalatest" % "3.2.18" % Test,
"org.scalatestplus" %% "scalacheck-1-15" % "3.2.9.0" % Test

)

These dependencies are essential for building and testing Akka HTTP applications.

Features for Building a Bookstore App

  • Create Books: Implement functionality to add new books to the bookstore database.
  • Fetch Books: Develop endpoints to retrieve all books or a specific book by its unique ID.
  • Check Book Inventory: Implement methods to determine the current stock availability of books.
  • Update Book Inventory: Provide endpoints to modify the quantity of a specific book in the inventory.

Step-by-Step Guide to Building a Bookstore App

Step 1: Define Book Case Class
Define a Book case class with essential parameters:

case class Book(name:String,author:String,publishedYear:Int,quantity:Int)

2. Step 2: Implement JSON Serialization:
Implement JSON serialization using Spray JSON:

a. create a trait and extend it to DefaultJsonProtocol

b. Now, create an implicit value in the following manner

import spray.json._

trait BookJsonProtocol extends DefaultJsonProtocol {
implicit val bookProtocol = jsonFormat4(Book)

}

Step 3: Create Actor for Business Logic:
Create an actor to handle business logic and data processing:

class BookActor extends Actor with ActorLogging {
override def receive: Receive ={
case GetAllBooks=>
log.info(s"Getting All the Books From the BookStoreDB")
sender() ! bookStoreDB.values.toList

case GetBookById(id)=>
log.info(s"Getting Book By Id $id")
sender() ! bookStoreDB.get(id)

// Add implementation for other messages

}

Step 4: Define API Endpoints
Define API endpoints using Akka-Http-LowLevel for CRUD operations:

1. Fetch All Books

GET /api/books
This endpoint retrieves all books in the store.

2. Fetch a Specific Book

GET /api/books?id=<book_id>
This endpoint fetches details of a specific book by its ID.

3. Check Book Inventory

GET /api/books/inventory?instock=<true|false>
This endpoint checks which books are currently in stock (i.e., have a non-zero quantity) or out of stock.

4. Create a New Book

POST /api/books
This endpoint allows you to add a new book to the store. The request body should be a JSON representation of the book.

5. Update Book Inventory

POST /api/books/inventory?id=<book_id>&quantity=<new_quantity>
This endpoint updates the quantity of a specific book in the store.

Step 5: Start Akka-Http-LowLevel Server
Initialize and start the server:

object CodinoverseBookStoreApp extends App{

val bindingServer = Http().newServerAt("localhost",8085).bind(requestHandler)

StdIn.readLine()
bindingServer
.flatMap(_.unbind()) // Trigger unbinding from the port
.onComplete(_ => system.terminate()) // And shutdown when done

Await.result(system.whenTerminated, Duration.Inf)
}

Conclusion

In this blog, we demonstrated how to build a low-level REST API for a bookstore using Akka-Http-LowLevel in Scala. We covered the setup, installation, running the server, and detailed descriptions of the available API endpoints. This simple API can serve as a starting point for more complex applications and showcases the power and flexibility of Akka-Http-LowLevel for building RESTful services in Scala.

For the entire implementation, refer to this GitHub repository.

https://github.com/codinoverse/akka-http-lowLevelApi

--

--