REST API Project in Scala
In this lesson, you will build a REST API using Scala. This project brings together concepts you have already learned—data processing, functional programming, immutability, and error handling—into a real-world backend service.
You will learn how to define endpoints, handle HTTP requests, process data, and return JSON responses in a clean and scalable way.
What Is a REST API?
A REST API (Representational State Transfer) allows systems to communicate over HTTP. Clients send requests, and servers respond with structured data—usually JSON.
Common HTTP methods include:
GET– retrieve dataPOST– create dataPUT– update dataDELETE– remove data
Project Overview
We will build a simple User Management REST API that supports:
- Fetching all users
- Fetching a single user by ID
- Adding a new user
This mirrors real backend APIs used in production systems.
Project Structure
A typical Scala REST project looks like this:
models– data modelsroutes– API endpointsservices– business logicserver– HTTP server configuration
Defining the Data Model
We start by defining a user model.
case class User(id: Int, name: String, email: String)
Case classes are ideal for APIs because they are immutable and concise.
Creating In-Memory Data Storage
For simplicity, we store users in memory.
var users = List(
User(1, "Alice", "alice@example.com"),
User(2, "Bob", "bob@example.com")
)
GET: Fetch All Users
This endpoint returns all users.
def getAllUsers(): List[User] = {
users
}
GET: Fetch User by ID
We locate a user using find.
def getUserById(id: Int): Option[User] = {
users.find(_.id == id)
}
Using Option prevents null-related errors.
POST: Add a New User
We add a new user to the list.
def addUser(user: User): List[User] = {
users = users :+ user
users
}
Handling JSON Data
REST APIs usually communicate using JSON. Scala libraries (like Play JSON or Circe) help serialize objects.
{
"id": 3,
"name": "Charlie",
"email": "charlie@example.com"
}
Processing API Requests
A REST endpoint typically:
- Receives a request
- Validates input
- Processes data
- Returns a response
Scala’s strong typing ensures safer APIs.
Error Handling in APIs
Errors should return meaningful responses.
def findUser(id: Int): Either[String, User] = {
getUserById(id).toRight("User not found")
}
This approach avoids throwing exceptions.
Why Scala Is Great for REST APIs
- Strong typing improves reliability
- Functional design leads to clean logic
- Excellent concurrency support
- Used in real-world backend systems
📝 Practice Exercises
Exercise 1
Create a function that deletes a user by ID.
Exercise 2
Modify the API to return an error if a user already exists.
Exercise 3
Add a function that updates a user’s email.
✅ Practice Answers
Answer 1
def deleteUser(id: Int): List[User] = {
users = users.filterNot(_.id == id)
users
}
Answer 2
def addUniqueUser(user: User): Either[String, List[User]] = {
if(users.exists(_.id == user.id))
Left("User already exists")
else {
users = users :+ user
Right(users)
}
}
Answer 3
def updateEmail(id: Int, newEmail: String): List[User] = {
users = users.map {
case u if u.id == id => u.copy(email = newEmail)
case u => u
}
users
}
What’s Next?
In the next lesson, you will explore Big Data & Spark with Scala, where these REST and data-processing skills scale to massive datasets.