I am new to play framework and trying to integrate a microservice. I am using WSClient to call a web service. In order to call a POST rest API, I am passing request body which contains some required parameters and some optional. My question is how to pass Optional parameters here?
My Code sample is
def add = Action.async { implicit request =>
UserDataForm.bindFromRequest.fold(
profileForm => {
val response = profileForm.errorsAsJson
Future(BadRequest(response).as("application/json"))
},
userData => try {
ws.url("http://localhost:9000/" + "api/profile")
.post(
Map("userId" -> userData.userId, "firstName" -> userData.firstName, "lastName" -> userData.lastName, "country" -> userData.country, "address" -> userData.address)).map { response =>
OutputWithErrors(response.body, response.status)
}
} catch {
case e: Exception =>
Future(BadRequest(Message(false, e.getMessage).toJson.prettyPrint).as("application/json"))
})
}
So here address
is optional parameter.
And form data i.e. userData
here
case class UserForm(userId: String, firstName: String, lastName: String, country: String, address: Option[String])
val UserDataForm = Form(
mapping(
"userId" -> nonEmptyText,
"firstName" -> nonEmptyText,
"lastName" -> nonEmptyText,
"country" -> nonEmptyText,
"address" -> optional(text)
)(UserForm.apply)(UserForm.unapply)
)
So while calling rest service API near ws.url(...)post(Map("userId" -> userData, ...))
compiler is complaining about No implicits found for parameter evidence$2: BodyWritable[Map[String, Serializable]]
The problem here is the Map
you are passing to post
. All but one entry is (String, String)
, but the last one is (String, Option[String])
.
The compiler now has to figure out what the type of this collection might be and goes up the type hierarchy. The best type it can figure out is Map[String, Serializable]
. Because that's the narrowest super type String and Option implement.
This is the definition for post:
def post[T: BodyWritable](body: T): Future[Response]
You can see there's a type constraint on T, which means that you need an implicit converter* for the body that is passed to post to BodyWritable
. You can find the implicit BodyWritables in DefaultBodyWritables. And there is no BodyWritable[Map[String, Serializable]]
. But there is one for Map[String, String]
You have to choices:
Map[String, String]
, either by providing a default value for address
via getOrElse
or don't add address to the map if it's None.I suggest you go with #1.
* please correct me if that's not the right term for these kind of implicits.