79

I am trying to issue a simple POST request to a webservice which returns some XML in Scala.

It seems that Dispatch is the standard library used for this task, but I cannot find documentation for it. The main site, which I link above, explains at length what is a promise and how to do asynchronous programming, but does not actually document the API. There is a periodic table - which looks a bit scary - but it only seems useful to people who already know what to do and only need a reminder for the cryptic syntax.

It also seems that Scalaz has some facility for HTTP, but I cannot find any documentation for it either.

Andrea
  • 20,253
  • 23
  • 114
  • 183
  • http://databinder.net/dispatch-doc/ – pr1001 Jul 30 '12 at 10:26
  • 1
    Thank you for the API. From that I may able to figure out how to actually use the library. Still, I would like to have something intermediate, like a high level description of the API. I imagine something along the lines of "To make a POST request, you use this constructor, with these parameters and so on". – Andrea Jul 30 '12 at 12:11
  • Agreed that Dispatch could use better documentation. I think your best bet for now is to ask on the Google Group: https://groups.google.com/forum/#!forum/dispatch-scala – pr1001 Jul 30 '12 at 14:37

9 Answers9

149

I use the following: https://github.com/scalaj/scalaj-http.

Here's a simple GET request:

import scalaj.http.{Http, HttpOptions}

Http("http://example.com/search").param("q", "monkeys").asString

and an example of a POST:

val result = Http("http://example.com/url").postData("""{"id":"12","json":"data"}""")
  .header("Content-Type", "application/json")
  .header("Charset", "UTF-8")
  .option(HttpOptions.readTimeout(10000)).asString

Scalaj HTTP is available through SBT:

libraryDependencies += "org.scalaj" % "scalaj-http_2.11" % "2.3.0"
ahajib
  • 12,838
  • 29
  • 79
  • 120
kulikov
  • 1,604
  • 1
  • 10
  • 2
  • I turns out to be the simplest option! I am still curious to learn about Dispatch and the reason of its peculiar syntax – Andrea Jul 30 '12 at 12:22
  • 10
    Note: the default connection timeout is pretty low (100 millis), so if you are receiving a `java.net.SocketTimeoutException: connect timed out`, then add a line such as `.option(HttpOptions.connTimeout(10000))` – theon Jun 09 '13 at 15:45
  • 1
    It's not compatible with scala 2.11 anymore since they removed ScalaObject. Waiting eagerly for scalaj-http to update their library. – Nativ Dec 10 '14 at 12:57
  • 2
    @Dalvik I think they've cleaned their game; just add `"org.scalaj" %% "scalaj-http" % "1.1.4"` to build.sbt. – Felipe Mar 30 '15 at 18:32
  • I'm not sure if anyone else has had trouble getting a response with "asParamsMap" on post, but I ended up having to use "asString" and then parsing explicitly with net.minidev.json.parser.JSONParser. – th3morg Aug 14 '15 at 13:17
  • What's wrong with using `scala.io.Source.fromURL(url).mkString`? I guess you can't use headers and some other options - but for a truly simple get request, what else do you need? – DanGordon Oct 26 '16 at 20:26
  • It's interesting how the execute is called from asString apart from other areas in that library – Kumar Vaibhav Dec 24 '16 at 02:30
  • check https://mvnrepository.com/artifact/org.scalaj/scalaj-http for the latest versions of scalaj http – Ariel Mirra Nov 11 '19 at 14:09
  • You need to call the execute method of Http in order to make the actual connection and get a response, I have no idea why the author of this post didn't include that information... – pavel_orekhov Feb 12 '21 at 13:52
  • can anyone tell me if there is any way to increase the response size like how we increase the timeout – Praneeth Sai Mar 05 '22 at 16:01
  • 1
    Just heads up, The repository has been archived by the owner on Apr 4, 2022. It is now read-only. This is based on the message from https://github.com/scalaj/scalaj-http – user3508953 Mar 09 '23 at 22:37
7

You could use spray-client. The documentation is lacking (it took me some digging to find out how to make GET requests with query parameters) but it's a great option if you are already using spray. And the documentation is better than dispatch.

We're using it at AI2 over dispatch because the operators are less symbolic and we're already using spray/actors.

import spray.client.pipelining._

val url = "http://youruri.com/yo"
val pipeline: HttpRequest => Future[HttpResponse] = sendReceive

// Post with header and parameters
val responseFuture1: Future[String] = pipeline(Post(Uri(url) withParams ("param" -> paramValue), yourPostData) map (_.entity.asString)

// Post with header
val responseFuture2: Future[String] = pipeline(Post(url, yourPostData)) map (_.entity.asString)
Community
  • 1
  • 1
schmmd
  • 18,650
  • 16
  • 58
  • 102
  • The main spray developer moved to akka, so even that spray is production ready, will be outdated, and AKKA-HTTP and AKKA-STREAMS will be the next round for http clients and servers. http://akka.io/docs/ – Henry H. Nov 10 '15 at 08:38
6

Using my Requests-Scala library:

// Mill
ivy"com.lihaoyi::requests:0.1.8"
// SBT
"com.lihaoyi" %% "requests" % "0.1.8"

This is as simple as

val r = requests.get("https://api.github.com/users/lihaoyi")

r.statusCode
// 200

r.headers("content-type")
// Buffer("application/json; charset=utf-8")

r.text
// {"login":"lihaoyi","id":934140,"node_id":"MDQ6VXNlcjkzNDE0MA==",...
val r = requests.post("http://httpbin.org/post", data = Map("key" -> "value"))

val r = requests.put("http://httpbin.org/put", data = Map("key" -> "value"))

val r = requests.delete("http://httpbin.org/delete")

val r = requests.head("http://httpbin.org/head")

val r = requests.options("http://httpbin.org/get")
Li Haoyi
  • 15,330
  • 17
  • 80
  • 137
  • Awesome Li,I also have some doubt, what about if I want to give Json to data in requests.post, do I have to extract the each key value pairs. Is there not a simple approach. – Mohammad Rijwan Nov 29 '19 at 10:02
  • I got it, val json = """{"key":"value"}""".stripMargin val r = requests.post(url,data=json) val json = ujson.read(r.text()) println(json) – Mohammad Rijwan Nov 29 '19 at 10:14
4

I'm using dispatch: http://dispatch.databinder.net/Dispatch.html

They've just released a new version (0.9.0) with a complete new api that I really like. And it is async.

Example from project page:

import dispatch._
val svc = url("http://api.hostip.info/country.php")
val country = Http(svc OK as.String)

for (c <- country)
  println(c)

edit: This might help you https://github.com/dispatch/reboot/blob/master/core/src/main/scala/requests.scala

drexin
  • 24,225
  • 4
  • 67
  • 81
  • Yes, I linked the project page. But I cannot find there how to make a simple POST request - or even a GET request with parameters and/or custom headers. – Andrea Jul 30 '12 at 12:07
  • @Andrea - try this link: http://www.flotsam.nl/dispatch-periodic-table.html . It seems that `dispatch` author has some problems with main doc at the moment - just yesterday the docs were much better. – Rogach Jul 30 '12 at 12:41
  • @Rogach isn't that just for the old dispatch? Andrea: updated my post with a link to the sources – drexin Jul 30 '12 at 13:07
  • it can now: `val svc = url("http://diasporafoundation.org/").POST.setBody("test")` – VasiliNovikov Dec 21 '13 at 12:20
3

Another option is Typesafe's play-ws, which is the Play Framework WS library broken out as a standalone lib:

http://blog.devalias.net/post/89810672067/play-framework-seperated-ws-library

I wouldn't necessarily offer this as the best option, but worth mentioning.

tksfz
  • 2,932
  • 1
  • 23
  • 25
2

If I can make a shameless plug, I have an API called Bee-Client which is simply a wrapper in Scala for Java's HttpUrlConnection.

Rick-777
  • 9,714
  • 5
  • 34
  • 50
  • Thank you. Is there any documentation available? – Andrea Jul 31 '12 at 07:51
  • Yes but it's quite limited still. I'm working on some example usages. For now, have a look at the test code, especially the integration test https://bitbucket.org/rickb777/lighthttpclient/src/a6c526e4684b/src/test/scala/uk/co/bigbeeconsultants/http/HttpIntegration.scala – Rick-777 Jul 31 '12 at 08:03
  • There is now some documentation on the wiki https://bitbucket.org/rickb777/lighthttpclient/wiki/Home – Rick-777 Aug 01 '12 at 12:10
  • Good! But it seems to be private. I do not have my Bitbucket credentials right now. Probably you forgot to mark the wiki as public – Andrea Aug 01 '12 at 14:23
  • Sorry for that. I moved the docs to my webserver instead: http://www.bigbeeconsultants.co.uk/light-http-client I've expanded the documentation too. – Rick-777 Aug 16 '12 at 08:20
  • The documentation has since moved to http://www.bigbeeconsultants.co.uk/bee-client – Rick-777 Jun 10 '13 at 18:57
  • please Rick add support for scala 2.11 or indicate in the doc than it's only available for scala <=2.10 ...I was pretty interested in use it but unfortunately seems than I can't because I'm stuck with scala 2.11 now.... – clagccs Sep 08 '14 at 23:16
  • Scala 2.11 support is almost ready for release. The remaining question is mostly whether to continue 2.9 support. – Rick-777 Sep 10 '14 at 12:32
  • Version 0.28.0 supports Scala 2.11. – Rick-777 Sep 14 '14 at 11:41
  • Upvoted strictly for *shameless plug*. Well done, sir. – domdambrogia Oct 26 '18 at 00:36
1

I had to do the same to test one end point (in Integration test). So following is the code to fetch response from GET request in Scala. I am making use of scala.io.Source to read from endpoint and ObjectMapper for json to object conversion.

private def buildStockMasterUrl(url:String, stockStatus:Option[String]) = {
      stockStatus match  {
        case Some(stockStatus) => s"$url?stockStatus=${stockStatus}"
        case _ => url
    }
  }

    private def fetchBooksMasterData(stockStatus:Option[String]):  util.ArrayList[BooksMasterData] = {
    val url: String = buildBooksMasterUrl("http://localhost:8090/books/rest/catalogue/booksMasterData",stockStatus)
    val booksMasterJson : String = scala.io.Source.fromURL(url).mkString
    val mapper = new ObjectMapper()
    apper.readValue(booksMasterJson,classOf[util.ArrayList[BooksMasterData]])
}

case class BooksMasterData(id:String,description: String,category: String)

And here is my test method for the same

test("validate booksMasterData resource") {
    val booksMasterData = fetchBooksMasterData(Option(null))
    booksMasterData.size should be (740)
  }
Sanjay Bharwani
  • 3,317
  • 34
  • 31
0

Why not use Apache HttpComponents ? Here's the application FAQ, which covers a wide range of scenarios.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
0

Here is a class I was working on. It has both GET and POST requests. GET without parameters - POST with parameters I used it to communicate with StreamSets in order to start a pipeline or check a pipeline status.

it only need the following dependency in the build.sbt file:

libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.3.0"

You can find the documentation here: https://github.com/scalaj/scalaj-http#post-raw-arraybyte-or-string-data-and-get-response-code


import scala.collection.mutable.ArrayBuffer
import scalaj.http.{Http, HttpResponse}

object HttpRequestHandler {

  val userName: String = "admin"
  val password: String = "admin"

  def sendHttpGetRequest(request: String): String = {

    println(" Send Http Get Request (Start) ")

    try {

      val httpResponse: HttpResponse[String] = Http(request).auth(userName,password)
                                                            .asString

      val response = if (httpResponse.code == 200) httpResponse.body
      else{
        println("Bad HTTP response: code = "+httpResponse.code )
        return "ERROR"
      }

      println(" Send Http Get Request (End) ")

      return response

    } catch {
      case e: Exception => println("Error in sending Get request: "+e.getMessage)
        return "ERROR"
    }


  }

  def arrayBufferToJson(params:ArrayBuffer[(String,String)]): String ={

    var jsonString = "{"
    var count: Int = 0
    for(param <- params){
      jsonString+="\""+param._1+"\":\""+param._2+"\""+ ( if(count!=params.length-1) "," else "")
      count+=1
    }
    jsonString+="}"

    return jsonString

  }

  def sendHttpPostRequest(request: String,params: ArrayBuffer[(String,String)]): String = {

    println(" Send Http Post Request (Start) ")

    try {
      val postData : String = arrayBufferToJson(params)
      println("Parameters: "+postData)
      val httpResponse: HttpResponse[String] = Http(request).auth(userName,password)
                                                            .header("X-Requested-By","sdc")
                                                            .header("Content-Type", "application/json;charset=UTF-8")
                                                            .header("X-Stream" , "true")
                                                            .header("Accept", "application/json")
                                                            .postData(postData.getBytes)
                                                            .asString


      val response = if (httpResponse.code == 200) httpResponse.body
      else{
        println("Bad HTTP response: code = "+httpResponse.code )
        "ERROR"
      }

      println(" Send Http Post Request (End) ")

      return response

    } catch {
      case e: Exception => println("Error in sending Post request: " + e.getMessage)
        return "ERROR"
    }
  }

}

Matrix
  • 1,810
  • 1
  • 19
  • 20