Sending HTTP Requests in 5 Minutes With Scala and Akka HTTP

This article is for the Scala programmer who wants to run one-off HTTP requests quickly. The thinking style assumed is, "I don't want to care too much. I'll give you a payload; you just give me a future containing your response". With minimal boilerplate, we'll do exactly that with Akka HTTP in 5 minutes.

You can find this article in video form on YouTube or embedded below.

The Rock the JVM blog is built with me typing my posts in plain text with minimal Markdown formatting and then generating a uniform HTML out of it, with a simple Scala parser (I hate typing HTML). For syntax highlighting, I use an online highlighter, which happens to have a REST endpoint.

Naturally, I don't want to do it by hand, so as my HTML is generated, the syntax is automatically retrieved via an Akka HTTP as client, with little code. My HMTL generator currently has less than 100 lines of code in total.

In this article, I'm going to get you started with the simplest Akka HTTP client API in 5 minutes.

The Tiny Setup

First, you need to add the Akka libraries. Create an SBT project in your dev environment (I recommend IntelliJ). Then, add this to the build.sbt file. (If you've never used SBT before, the build.sbt file describes all the libraries that the project needs, which the IDE will download automatically)
Scala
 




x
10


 
1
val akkaVersion = "2.5.26"
2
val akkaHttpVersion = "10.1.11"
3

           
4
libraryDependencies ++= Seq(
5
  // akka streams
6
  "com.typesafe.akka" %% "akka-stream" % akkaVersion,
7
  // akka http
8
  "com.typesafe.akka" %% "akka-http" % akkaHttpVersion,
9
  "com.typesafe.akka" %% "akka-http-spray-json" % akkaHttpVersion,
10
)



Then, in a Scala application, I'm going to write a piece of small boilerplate because Akka HTTP needs an actor system to run:
Scala
 




xxxxxxxxxx
1


 
1
implicit val system = ActorSystem()
2
implicit val materializer = ActorMaterializer()
3
import system.dispatcher



Sending HTTP Requests

Now, we'll need to start sending HTTP requests. I'll use the exact HTTP API I'm using for the blog: http://markup.su/highlighter/api. The API says it needs GET or POST requests to /api/highlighter, with the parameters "language", "theme", and "source" in a request with content type   application/x-www-form-urlencoded.

So, let me create a piece of Scala code:
Scala
 




xxxxxxxxxx
1
12


 
1
val source =
2
"""
3
  |object SimpleApp {
4
  |  val aField = 2
5
  |
6
  |  def aMethod(x: Int) = x + 1
7
  |
8
  |  def main(args: Array[String]) = {
9
  |    println(aMethod(aField))
10
  |  }
11
  |}
12
""".stripMargin



and then let me create an HTTP request for it:
Scala
 




xxxxxxxxxx
1


 
1
val request = HttpRequest(
2
    method = HttpMethods.POST,
3
    uri = "http://markup.su/api/highlighter",
4
    entity = HttpEntity(
5
      ContentTypes.`application/x-www-form-urlencoded`,
6
      s"source=${URLEncoder.encode(source.trim, "UTF-8")}&language=Scala&theme=Sunburst"
7
    )
8
  )



where I've named the arguments in the call for easy reading. In the Akka HTTP, an HttpRequest contains the HTTP method (POST in our case). The URI and a payload in the form of an HttpEntity. We specify the content type per the description specified in the API — notice the backticks for the name of the field — and the actual string we want to send, as described by the API. In practice, you can send other strings, like JSON — I'll show you how to auto-convert your data types to JSON auto-magically in another article.

Then, we actually need to send our request:
Scala
 




xxxxxxxxxx
1


 
1
  def simpleRequest() = {
2
    val responseFuture = Http().singleRequest(request)
3
    responseFuture.flatMap(_.entity.toStrict(2 seconds)).map(_.data.utf8String).foreach(println)
4
  }



The Akka HTTP client call is simple: just call the singleRequest method. You obtain a Future containing an HTTP response, which we can then unpack. We use its entity (= its payload) and convert it to a strict entity, meaning that we take its whole content in memory. We then take its data, which is a sequence of bytes, and convert that to a string. And we're done.

Hide it All

We can create a very nice method which hides this all away:
Scala
 




xxxxxxxxxx
1
16


 
1
  def highlightCode(myCode: String): Future[String] = {
2
    val responseFuture = Http().singleRequest(
3
      HttpRequest(
4
        method = HttpMethods.POST,
5
        uri = "http://markup.su/api/highlighter",
6
        entity = HttpEntity(
7
          ContentTypes.`application/x-www-form-urlencoded`,
8
          s"source=${URLEncoder.encode(myCode.trim, "UTF-8")}&language=Scala&theme=Sunburst"
9
        )
10
      )
11
    )
12

           
13
    responseFuture
14
      .flatMap(_.entity.toStrict(2 seconds))
15
      .map(_.data.utf8String)
16
  }



And then you can go on with your day: pass a string, expect a future containing an HTML highlighting. All done!

If you want to practice sending HTTP requests as an exercise, you can use https://jsonplaceholder.typicode.com/ for dummy APIs, the same principle applies.

Rejection in Akka HTTP: Handle Errors Properly

Learn more about rejection in Akka HTTP and how it helps in handling error scenarios in your application.

In this blog, we will demonstrate rejection in the Akka HTTP and how it helps in handling error scenarios in our application. Let's get started.