I am working on a simple Finatra API example, but having trouble using a case class for the POST request when using more than one field in the request body.
Here is an example of my case class and controller:
class SaleResource extends Controller {
post("/sales") { sale: Sale =>
s"$sale"
}
}
case class Sale(
user: Option[String],
streetAddress: Option[String]
)
I send a post request to that route with the following request body JSON:
{
"user": "Foo Barrington",
"streetAddress":"Baz Street"
}
The response:
Sale(Some(Foo Barrington),None)
The response shows that the user is being properly deserialized, but for some reason I cannot get the streetAddress field to populate.
Also, I noticed when I set either of these fields to String
instead of Option[String]
I only get unsuccessful 500 responses.
Things I have tried:
Some(streetAddress)
to that fields string value or "none found" when it is None
. In these cases it still is saying streetAddress
is None
when it is not.curl
and Postman.I can always access the user field from the Sales
object, but never the streetAddress
(or any other field from the request body for that matter if I add test elements to the case class.
I would expect both fields to be recognized since they are both provided in the request. I am newer to Scala/Finatra in general, so it is possible I am just using the Finatra library or Case classes incorrectly.
EDIT: It seems as if changing the field names to not be mixed/camelcase fixes all issues, but this seems like odd behavior.
Finatra uses Jackson library behind the scenes. The default configuration uses PropertyNamingStrategy.SNAKE_CASE
which seems like:
{
"user": "Foo Barrington",
"street_address":"Baz Street"
}
You need to change it to PropertyNamingStrategy.LOWER_CAMEL_CASE
to parse that JSON.
In order to do that, you need to define a custom FinatraJacksonModule
and tell the app to
use it.
object CustomFinatraJacksonModule extends FinatraJacksonModule {
override val propertyNamingStrategy = PropertyNamingStrategy.LOWER_CAMEL_CASE
}
class MyFinatraHttpServer extends HttpServer {
override protected def jacksonModule: Module = CustomFinatraJacksonModule
}
Jackson Integration provides more information about the topic.