could not find implicit value for evidence parameter of type ^

Lena Bru picture Lena Bru · Dec 12, 2016 · Viewed 8.5k times · Source

I am trying to write a test for a Post request

here is my code :

val request = CreateLinkRequest(token = Some(validToken),billing_ref_id = Some("123"), store_id = Some("123"), agent_id = Some("123"))

val endPoint = Uri(this.serverRootUrl + "path").toString
val post = Post(endPoint, request)
val pipeline = jsonAsStringPipeline(post)
val responseContents = Await.ready(pipeline, atMost = callMaxWaitDuration)

But this doesnt compile, I keep getting this error :

Error:(156, 20) could not find implicit value for evidence parameter of type spray.httpx.marshalling.Marshaller[CreateLinkSpec.this.CreateLinkRequest]
    val post = Post(endPoint, request)
               ^
Error:(156, 20) not enough arguments for method apply: (implicit evidence$1: 

spray.httpx.marshalling.Marshaller[CreateLinkSpec.this.CreateLinkRequest])spray.http.HttpRequest in class RequestBuilder.
Unspecified value parameter evidence$1.
    val post = Post(endPoint, request)
                   ^

What does this mean?

How can I fix it ?

EDIT: this is the json in the body :

{ token:"123", billing_ref_id:"123", store_id:"123", agent_id:"123"}

and this is the object for it in the code:

private final case class CreateLinkRequest(
    token: Option[String] = Some(validToken),
    billing_ref_id: Option[String] = Some(Random.alphanumeric.take(10).mkString),
    agent_id: Option[String] = Some(Random.alphanumeric.take(3).mkString),
    store_id: Option[String] = Some(Random.alphanumeric.take(3).mkString)
    )

Answer

Nikola Stojiljkovic picture Nikola Stojiljkovic · Dec 12, 2016

You are trying to call Post method which takes implicit Marshaller as parameter. Note that implicit parameters don't have to be provided as long as the compiler can find one in the scope (check this for more info about implicits: Where does Scala look for implicits?)

However, your code doesn't have any implicit Marshaller defined so the compiler doesn't know how to convert your case class into the HttpEntity.

In your case you want it to be converted into the HttpEntity with Content-Type: application/json. To do that you just need to define: implicit val CreateLinkRequestMarshaller: Marshaller[CreateLinkRequest]. This tells scala how to convert your case class into the HttpEntity.

You also want it to be passed to the context as JSON, so we are going to define our JsonProtocol, i.e. MyJsonProtocol.

package test

import spray.http.HttpEntity
import spray.http._
import spray.json._
import spray.httpx.marshalling.{Marshaller, MarshallingContext}
import test.TestMarshaller.CreateLinkRequest


object MyJsonProtocol extends DefaultJsonProtocol {
  implicit def createLinkRequestFormat: JsonFormat[CreateLinkRequest] = jsonFormat4(CreateLinkRequest)
}

object TestMarshaller extends App {
  import MyJsonProtocol._

  case class CreateLinkRequest(token: Option[String], billing_ref_id: Option[String], store_id: Option[String], agent_id: Option[String])

  implicit val CreateLinkRequestMarshaller: Marshaller[CreateLinkRequest] = new Marshaller[CreateLinkRequest] {
    override def apply(value: CreateLinkRequest, ctx: MarshallingContext): Unit = {
      val entity = HttpEntity(MediaTypes.`application/json`, value.toJson.compactPrint)
      ctx.marshalTo(entity)
    }
  }

  // Here goes your test
}

Note that you can define these implicits somewhere else, e.g. a package and then just import it in the test class. This would be better because you will certainly want to reuse the Marshaller.