Model definition

Let's make a simple JSON API in scala-cli.
Create a file json_api.sc and paste this code into it:

    //> using scala "3.4.0"
//> using dep ba.sake::sharaf:0.4.0

import io.undertow.Undertow
import ba.sake.tupson.JsonRW
import ba.sake.sharaf.*, routing.*

case class Car(brand: String, model: String, quantity: Int) derives JsonRW

var db: Seq[Car] = Seq()


Here we defined a Car model, which derives JsonRW, so we can use the JSON support from Sharaf.

We also use a var db: Seq[Car] to store our data.
(don't do this for real projects)

Routes definition

Next step is to define a few routes for getting and adding cars:

val routes = Routes:  
  case GET() -> Path("cars") =>
    Response.withBody(db)

  case GET() -> Path("cars", brand) =>
    val res = db.filter(_.brand == brand)
    Response.withBody(res)

  case POST() -> Path("cars") =>
    val reqBody = Request.current.bodyJson[Car]
    db = db.appended(reqBody)
    Response.withBody(reqBody)

The first route returns all data in the database.

The second route does some filtering on the database.

The third route binds the JSON body from the HTTP request.
Then we add it to the database.

Running the server

Finally, start up the server:

    Undertow.builder
  .addHttpListener(8181, "localhost")
  .setHandler(
    SharafHandler(routes).withExceptionMapper(ExceptionMapper.json)
  )
  .build
  .start()

println(s"Server started at http://localhost:8181")

and run it like this:

scala-cli json_api.sc 

Then try the following requests:

# get all cars
curl http://localhost:8181/cars

# add a car
curl --request POST \
  --url http://localhost:8181/cars \
  --data '{
    "brand": "Mercedes",
    "model": "ML350",
    "quantity": 1
  }'

# get cars by brand
curl http://localhost:8181/cars/Mercedes