POST request with JSON in Dispatch and Scala

5.8k views Asked by At

I'm having trouble making a POST request with a JSON object using Dispatch and Scala.

The POST request works fine for sure since I tested it using curl:

~/workspace $ curl -vd 'tracker={"project":"campaign","event":"home","number":"100"}'  http://exampleurl:8145/test

and I get a HTTP 200 response as expected

But when I try doing the same using Dispatch library ( http://dispatch.databinder.net/Dispatch.html ) like so:

scala> Http(url("http://exampleurl:8145/test") << "tracker={'project':'campaign','event':'home','number':'100'}" >|)

this is what I get:

dispatch.StatusCode: Unexpected response code: 404
Paramerter missing: [tracker] not found
at dispatch.HttpExecutor$$anonfun$when$1.apply(executor.scala:53)
at dispatch.HttpExecutor$$anonfun$when$1.apply(executor.scala:50)
at dispatch.HttpExecutor$$anonfun$x$2.apply(executor.scala:41)
at dispatch.HttpExecutor$$anonfun$x$2.apply(executor.scala:36)
at dispatch.BlockingHttp$$anonfun$execute$1.apply(Http.scala:54)
at dispatch.Http.pack(Http.scala:25)
at dispatch.BlockingHttp$class.execute(Http.scala:53)
at dispatch.Http.execute(Http.scala:21)
at dispatch.HttpExecutor$class.x(executor.scala:36)
at dispatch.Http.x(Http.scala:21)
at dispatch.HttpExecutor$class.when(executor.scala:50)
at dispatch.Http.when(Http.scala:21)
at dispatch.HttpExecutor$class.apply(executor.scala:60)
at dispatch.Http.apply(Http.scala:21)
at .<init>(<console>:11)
at .<clinit>(<console>)
at .<init>(<console>:11)
at .<clinit>(<console>)
at $print(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
at scala.tools.nsc.interpreter.IMain$Request.loadAndRun(IMain.scala:914)
at scala.tools.nsc.interpreter.IMain.loadAndRunReq$1(IMain.scala:546)
at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:577)
at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:543)
at scala.tools.nsc.interpreter.ILoop.reallyInterpret$1(ILoop.scala:694)
at scala.tools.nsc.interpreter.ILoop.interpretStartingWith(ILoop.scala:745)
at scala.tools.nsc.interpreter.ILoop.command(ILoop.scala:651)
at scala.tools.nsc.interpreter.ILoop.processLine$1(ILoop.scala:542)
at scala.tools.nsc.interpreter.ILoop.loop(ILoop.scala:550)
at scala.tools.nsc.interpreter.ILoop.process(ILoop.scala:822)
at scala.tools.nsc.interpreter.ILoop.main(ILoop.scala:851)
at xsbt.ConsoleInterface.run(ConsoleInterface.scala:57)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at sbt.compiler.AnalyzingCompiler.call(AnalyzingCompiler.scala:57)
at sbt.compiler.AnalyzingCompiler.console(AnalyzingCompiler.scala:48)
at sbt.Console.console0$1(Console.scala:23)
at sbt.Console$$anonfun$apply$2$$anonfun$apply$1.apply$mcV$sp(Console.scala:24)
at sbt.TrapExit$.executeMain$1(TrapExit.scala:33)
at sbt.TrapExit$$anon$1.run(TrapExit.scala:42)

I'm not sure why it's missing the tracker parameter that I'm trying to pass through.

Thoughts anyone?

2

There are 2 answers

1
Dave Whittaker On BEST ANSWER

I think you want to post it as a name value pair:

Http(url("http://exampleurl:8145/test") << 
  Map("tracker" -> "{'project':'campaign','event':'home','number':'100'}") >|)
0
sralmai On

Not sure about your version of dispatch, but another way to do this (in version 0.11.0, at least) (especially if it is not convenient to mash your data back into a Map) is to explicitly set the the content type, like this:

Http(url("http://exampleurl:8145/test").setBody(
     "tracker={'project':'campaign','event':'home','number':'100'}").setHeader(
     "Content-Type", "application/json") OK as.String)

NOTE: I removed the ">|" operator (which is from dispatch 0.8.x and ignores the response) with "OK as.String". Feel free to ignore that response string.

This is nice in the case that you are using lift-json with case classes (or just mangling with the AST in general). Then instead of

Http(url("http://someplace.com") << someAwfulTransformer(
     myCaseClassOrBigASTbasedThing) OK as.String)

you can do this

Http(url("http://someplace.com").setBody(
     write(myCaseClassOrBigASTbasedThing)).setHeader(
     "Content-Type", "application/json") OK as.String)

Feel free to decorate this with your implicits or helper functions to minimize typing. But the point is that if you have a direct entity to JSON string mapping, you don't need to worry about transforming it back into a Map. In fact, you shouldn't.