POST request using spray-client - scala

I want to send XML over HTTP POST request to server using spray-client with some headers set etc. However, only examples that I can find are for JSON requests.
Can somebody provide a simple snippet of code for XML over HTTP POST communication using spray-client?
Thanks!

Here is a small code sample for creating a spray HttpRequest that has an xml NodeSeq based payload. Let me know if you this helps or if you need more code (like submitting the request):
import spray.httpx.RequestBuilding._
import spray.http._
import HttpMethods._
import HttpHeaders._
import MediaTypes._
object SprayXml {
def main(args: Array[String]) {
val xml = <root>foo</root>
val req = Post("/some/url", xml)
}
}
The two dependencies I was using to make this code work are spray-client and spray-httpx.
The relevant pieces from my build.sbt are:
scalaVersion := "2.10.0"
resolvers ++= Seq(
"Scala Tools Repo Releases" at "http://scala-tools.org/repo-releases",
"Typesafe Repo Releases" at "http://repo.typesafe.com/typesafe/releases/",
"spray" at "http://repo.spray.io/"
)
libraryDependencies ++= Seq(
"io.spray" % "spray-httpx" % "1.1-M7",
"io.spray" % "spray-client" % "1.1-M7",
"com.typesafe.akka" %% "akka-actor" % "2.1.0"
)

With a hacky way to be specific about the content type. Note payload can be string or xml literal.
import spray.client.pipelining._
import spray.http._
val pipeline: HttpRequest => Future[HttpResponse] = {
addHeader("My-Header-Key", "myheaderdata") ~>
((_:HttpRequest).mapEntity( _.flatMap( f => HttpEntity(
f.contentType.withMediaType(MediaTypes.`application/xml`),f.data))))
~> sendReceive
}
pipeline(
Post(
"http://www.example.com/myendpoint", <MyXmlTag>MyXmlData</MyXmlTag>
)
)

Related

How to use a standalone WSClient in a Scala application

I would like to use ws in a standalone application. Trying this code, copied from https://gist.github.com/cdimascio/46b2b7d2986636c1189c :
import com.ning.http.client.AsyncHttpClientConfig
import play.api.libs.ws.ning._
import play.api.libs.ws._
// provide an execution context
import scala.concurrent.ExecutionContext.Implicits.global
object WSStandaloneTest {
def main(args: Array[String]) {
// set up the client
val config = new NingAsyncHttpClientConfigBuilder(DefaultWSClientConfig()).build
val builder = new AsyncHttpClientConfig.Builder(config)
val client = new NingWSClient(builder.build)
// execute a GET request
val response = client.url("http://www.example.com").get
// print the response body
response.foreach(r => {
println(r.body)
// not the best place to close the client,
// but it ensures we dont close the threads before the response arrives
// Good enough for the gist :-D
client.close()
})
}
}
Results in the following error:
[error] object ning is not a member of package play.api.libs.ws
[error] import play.api.libs.ws.ning._
In my build.sbt I have this:
libraryDependencies += "com.typesafe.play" %% "play-json" % "2.6.1"
libraryDependencies += "com.typesafe.play" %% "play-ws" % "2.6.1"
What am I doing wrong?
NingWSClient is deprecated in Play! 2.5.x.
In 2.6.x
The ning package has been replaced by the ahc package, and the Ning* classes replaced by AHC*.
There is a migration guide available in the official doc.
So you can choose to downgrade to 2.5.x and use ning or update the code.

Unable to import DefaultHttpFilters

I'm attempting to create a filter to collect metrics related to request fulfillment time in a Scala Play 2.5 app. I am following this documentation.
It instructs me to create a class that extends DefaultHttpFilters. However, I am unable to import this class! import play.api.http.DefaultHttpFilters is unrecognized. It occurred to me that I may need to make an addition to build.sbt, so I added filters to libraryDependencies in that file, but still no luck. The truly strange thing is that import play.api.http.HttpFilters is recognized. DefaultHttpFilters lives in the same package, and in fact implements the HttpFilters trait, so I'm rather bamboozled by the fact that the import is unrecognized.
Any advice would be greatly appreciated, and please let me know if I can provide any further information to help in diagnosing the issue.
Here is my build.sbt:
name := """REDACTED"""
version := "1.0.0"
lazy val root = (project in file(".")).enablePlugins(PlayScala)
scalaVersion := "2.11.7"
routesGenerator := InjectedRoutesGenerator
resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases"
libraryDependencies ++= Seq(
ws,
filters,
"com.typesafe.play" %% "play-slick" % "2.0.0",
"com.h2database" % "h2" % "1.4.187",
"org.scalatestplus.play" %% "scalatestplus-play" % "1.5.0" % "test",
"mysql" % "mysql-connector-java" % "5.1.39",
specs2 % Test
)
unmanagedJars in Compile += file(Path.userHome+"/lib/*.jar")
resolvers += "Sonatype snapshots" at "http://oss.sonatype.org/content/repositories/snapshots/"
fork in run := true
Here is plugins.sbt:
resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.0")
addSbtPlugin("com.jamesward" %% "play-auto-refresh" % "0.0.14")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.3.5")
Filters are defined in the following way
app/filters/AccessLoggingFilter.scala:
import javax.inject.Inject
import akka.stream.Materializer
import play.api.Logger
import play.api.mvc.{Filter, RequestHeader, Result}
import play.api.routing.Router.Tags
import scala.concurrent.Future
class AccessLoggingFilter #Inject() (implicit val mat: Materializer) extends Filter {
def apply(nextFilter: RequestHeader => Future[Result])(requestHeader: RequestHeader): Future[Result] = {
val requestStartTime = System.nanoTime
nextFilter(requestHeader).map { result =>
val requestedAction = requestHeader.tags(Tags.RouteController) + "." + requestHeader.tags(Tags.RouteActionMethod)
val requestFulfillmentTime = System.nanoTime - requestStartTime
Logger.info("Request for " + requestedAction + " resulted in status code " + result.header.status +
" and had request fulfillment time " + requestFulfillmentTime + " nanoseconds")
result.withHeaders("Request-Time" -> requestFulfillmentTime.toString)
}
}
}
And then app/filters/Filters.scala:
package filters
import javax.inject.Inject
class Filters #Inject() (accessLoggingFilter: AccessLoggingFilter) { }
DefaultHttpFilters was only introduced in Play 2.5.4, and you are using Play 2.5.0.
So change your Play version to 2.5.4 at least (the current version at the time of writing is 2.5.6)
// In plugins.sbt
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.4")
Then, just reload the project and update your dependencies (activator update)
If you really need to use that version, use HttpFilters instead (same example from "Using filters")
import javax.inject.Inject
import play.api.http.HttpFilters
import play.filters.gzip.GzipFilter
class Filters #Inject() (
gzip: GzipFilter,
log: LoggingFilter
) extends HttpFilters {
val filters = Seq(gzip, log)
}

Get content from Akka ResponseEntity in Scala

I do a GET HTTP call to a rest service which returns a json. I would like to parse the json to a scala object but here I got stuck. I am using the Akka api and I can't manage to retrieve the content from the Akka's ResponseEntity
Here is my sbt file:
name := "ScalaHttp"
version := "1.0"
scalaVersion := "2.11.8"
libraryDependencies ++={
val akkaV = "2.4.5"
Seq(
"com.typesafe.akka" %% "akka-http-core" % akkaV,
"com.typesafe.play" %% "play-json" % "2.4.0-M3"
)
}
And here is the app
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.HttpRequest
import akka.stream.ActorMaterializer
import scala.concurrent.ExecutionContext.Implicits.global
object Sender {
def main(args: Array[String]): Unit = {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
Http().singleRequest(HttpRequest(uri = "http://declinators.com/declinator?noun=komunikacja")) foreach {
y => println(y.entity)
println(y.entity.getContentType())
println(y.entity.contentType)
}
}
}
This prints:
HttpEntity.Strict(application/json,{"nominative":"komunikacja","genitive":"komunikacji","dative":"komunikacji","accusative":"komunikacjÄ™","instrumental":"komunikacjÄ…","locative":"komunikacji","vocative":"komunikacjo"})
application/json
application/json
Here come the questions:
1. Why ResponseEntity supplies getContentType() and contentType()? They return the same thing.
2. Getting the contentyType is easy, you have two ways for doing it, but how can I get the content itself, so I can play (i.e. parse it using play) with the json!
You can use entity.data.toString for Binary content type, or the following code piece
data.decodeString(nb.charset.value)
Please follow the HttpEntity.Strict.toString implementation here for detail:
https://github.com/akka/akka/blob/master/akka-http-core/src/main/scala/akka/http/scaladsl/model/HttpEntity.scala#L316

Play: How to Create a Fake Request in Production Code

FakeRequest comes from artifact play-test and is added to the project only in the test scope... but I need to create a kind of fake request just to invoke a method that takes an implicit RequestHeader:
import play.api.test._
...
implicit val request = FakeRequest(
Helpers.POST,
controllers.routes.auth.Users.triggerPasswordReset(superuser.email.get).url,
FakeHeaders(),
""
)
// createToken takes an implict RequestHeader
createToken(TokenType.Reset, account).map { token =>
EmailHelper.sendPasswordResetEmail(user.email.get, token.asJwt)
...
}
How do I import FakeRequest in the compile scope? Is there a better option? Or shall I invoke the controller's method directly?
Add the following to your Build.sbt
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play-test" % "2.2.1" % "compile"
)
Make sure to change "2.2.1" to be whatever version of Play your are using.
This should expose the play test classes to the compile scope.
Cheers!

Error in hello world spray app with scala 2.11

I'm trying to get a simple "hello world" server running using spray with scala 2.11:
import spray.routing.SimpleRoutingApp
import akka.actor.ActorSystem
object SprayTest extends App with SimpleRoutingApp {
implicit val system = ActorSystem("my-system")
startServer(interface = "localhost", port = 8080) {
path("hello") {
get {
complete {
<h1>Say hello to spray</h1>
}
}
}
}
}
However, I receive the following compile errors:
Multiple markers at this line
- not found: value port
- bad symbolic reference to spray.can encountered in class file 'SimpleRoutingApp.class'. Cannot
access term can in package spray. The current classpath may be missing a definition for spray.can, or
SimpleRoutingApp.class may have been compiled against a version that's incompatible with the one
found on the current classpath.
- not found: value interface
Does anyone know what might be the issue? BTW, I'm very new to spray and actors, so I lack a lot of intuition for how spray and actors work (that's why I'm doing this simple tutorial).
Finally found the answer myself. I needed to add the spray-can dependency to my pom file. Leaving this question and answer in case anyone else runs into the same problem.
SBT example:
scalaVersion := "2.10.4"
val akkaVersion = "2.3.6"
val sprayVersion = "1.3.2"
resolvers ++= Seq(
"Spray Repository" at "http://repo.spray.io/"
)
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % akkaVersion,
"io.spray" %% "spray-can" % sprayVersion,
"io.spray" %% "spray-routing" % sprayVersion
)