Search code examples
scalarestcase-classfinatra

Trouble using case class for multiple fields in POST body Finatra


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:

  • case statements matching 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.
  • Making the request with both 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.


Solution

  • 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.