How to receive objects in query parameters

I wish to create an API endpoint that accepts objects as query parameters, like so:

http://localhost:9000/api/employees/128/intimations?start={month:12,year:2019}&end={month:28,year:2019}

In order to achieve the same I created Start and End case classes, like so:

case class Start(month: Int, year: Int)

object Start {
  implicit val format: Format[Start] = Json.format[Start]
}

case class End(month: Int, year: Int)

object End {
  implicit val format: Format[End] = Json.format[End]
}

And defined the service like so:

def getInactiveIntimations(empId: Long, start: Start, end: End): ServiceCall[NotUsed, Done]

restCall(Method.GET, "/api/employees/:id/intimations?start&end", getInactiveIntimations _)

However, I am getting a compile time error while service definition, saying:

[error] /home/codingkapoor/Personal/workspace/codingkapoor/intimations-platform/employee-api/src/main/scala/com/codingkapoor/employee/api/EmployeeService.scala:55:74: type mismatch;
[error]  found   : (Long, Option[com.codingkapoor.employee.api.model.Start], Option[com.codingkapoor.employee.api.model.End]) => com.lightbend.lagom.scaladsl.api.ServiceCall[akka.NotUsed,akka.Done]
[error]  required: com.lightbend.lagom.scaladsl.api.ServiceSupport.ScalaMethodServiceCall[?,?]
[error]         restCall(Method.GET, "/api/employees/:id/intimations?start&end", getInactiveIntimations _)
[error]                                                                          ^
[error] one error found
[error] (employee-api / Compile / compileIncremental) Compilation failed

Is it not possible to use objects as query parameters in Lagom? And if it’s possible, how to do so?

Hi @codingkapoor,

I do not use objects in query parameters but you could check Path-based-identifiers.

You can “register” custom PathParamSerializer in service descriptor (withPathParamSerializer).

Hope this helps.

Br,
Alan

2 Likes

Thanks for you reply but I don’t see withPathParamSerializer API available on a descriptor.

Although I couldn’t find withPathParamSerializer API available on a descriptor. I was able to get it working as per @aklikic suggestion by simply importing the defined implicit PathParamSerializer in the service descriptor class, like so:

case class MonthYear(month: Int, year: Int)

object MonthYear {
  implicit val format: Format[MonthYear] = Json.format[MonthYear]

  private def serializer(monthYear: MonthYear): String = Json.stringify(Json.toJson(monthYear))

  private def deserializer(str: String): MonthYear = Json.fromJson(Json.parse(str)).get

  implicit val monthYearPathParamSerializer: PathParamSerializer[MonthYear] = {
    PathParamSerializer.required[MonthYear]("MonthYear")(deserializer)(serializer)
  }
}

trait HolidayService extends Service {

  def getHolidays(start: MonthYear, end: MonthYear): ServiceCall[NotUsed, Seq[HolidayRes]]

  override final def descriptor: Descriptor = {
    import Service._
    import MonthYear._

    named("holiday")
      .withCalls(
        restCall(Method.GET, "/api/holidays?start&end", getHolidays _)
      )
  }
}

Hi @codingkapoor,

My apologize for the confusion, withPathParamSerializer is used in javadsl. And, as you already figured out, implicit for scaladsl.

Br,
Alan