scalaj-http

Simple Scala wrapper for Java HttpURLConnection. Lightweight with minimal dependencies, OAuth authentication support included. Simple API design specialized for basic HTTP operations, achieving quick HTTP communication without complex configuration. HTTP client with low learning cost.

HTTP ClientScalaLightweightOAuthZero Dependencies

GitHub Overview

scalaj/scalaj-http

Simple scala wrapper for HttpURLConnection. OAuth included.

Stars973
Watchers42
Forks119
Created:August 23, 2010
Language:Scala
License:Apache License 2.0

Topics

httpoauthscala

Star History

scalaj/scalaj-http Star History
Data as of: 7/18/2025, 01:39 AM

Library

scalaj-http

Overview

scalaj-http was a "simple Scala wrapper for HttpURLConnection" developed as a lightweight HTTP client library in the Scala ecosystem. Designed with emphasis on "zero dependencies and simplicity," it operated as a thin wrapper around Java's HttpURLConnection, providing OAuth 1.0 support, immutable object design, fluent API, and automatic compression handling. However, the project was archived in April 2022 and development has ended, and migration to modern alternatives like sttp or http4s is now recommended.

Details

scalaj-http 2.4.2 (final version) provided HTTP communication through a minimal wrapper around Java HttpURLConnection. With three main components—Http, HttpRequest, and HttpResponse—it achieved immutable and thread-safe HTTP client functionality. It featured zero dependencies (Base64 encoding and OAuth signing were implemented internally), immutable builder pattern, fluent API, automatic gzip/deflate compression, multipart uploads, and OAuth v1 signing capabilities. However, due to project termination, it is no longer maintained or updated, and its use in new projects is discouraged.

Key Features (Historical Reference)

  • Zero Dependencies: Complete standalone implementation without external library dependencies
  • Immutable Object Design: Thread-safe and reusable request construction
  • Fluent API: Intuitive request building through method chaining
  • OAuth 1.0 Support: Built-in OAuth signing functionality
  • Automatic Compression: Automatic decompression of gzip/deflate responses
  • Lightweight Implementation: High performance with minimal features

Pros and Cons

Pros (Historical Evaluation)

  • Lightweight and easy deployment due to zero external dependencies
  • Thread safety and predictability through immutable object design
  • Low learning cost due to simple and understandable API design
  • Proven track record in Google App Engine and Android environments
  • Simplified authentication integration through built-in OAuth 1.0 support
  • Stability and compatibility based on Java HttpURLConnection

Cons (Migration Reasons)

  • No maintenance or support due to project termination (archived April 2022)
  • Lack of modern features like asynchronous processing or connection pooling
  • No HTTP/2 support, no modern protocol support
  • Limited error handling and detailed control options
  • Insufficient functionality for large-scale applications
  • No security updates or new feature additions

Reference Pages

Migration Information

Important: scalaj-http was archived in April 2022 and development has ended. For new projects, we recommend using the following modern alternative libraries:

Recommended Alternatives

  1. sttp - Feature-rich HTTP client supporting various programming models
  2. http4s - HTTP library for functional programming
  3. Akka HTTP Client - Reactive streaming support
  4. Java HttpClient (JDK 11+) - Modern HTTP client in standard library

Code Examples (Historical Reference)

Installation (Final Version)

// build.sbt
libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2"
<!-- Maven pom.xml -->
<dependency>
  <groupId>org.scalaj</groupId>
  <artifactId>scalaj-http_2.13</artifactId>
  <version>2.4.2</version>
</dependency>

Basic HTTP Requests

import scalaj.http._

// Basic GET request
val response: HttpResponse[String] = Http("https://api.example.com/users")
  .param("page", "1")
  .param("limit", "10")
  .asString

println(response.body)         // Response body
println(response.code)         // HTTP status code
println(response.headers)      // Response headers
println(response.cookies)      // Cookies

// Reusable HttpRequest
val request: HttpRequest = Http("https://api.example.com/")
val responseOne = request.asString
val responseTwo = request.asString

// POST request with JSON data
val jsonData = """{"name": "John Doe", "email": "[email protected]"}"""
val postResponse = Http("https://api.example.com/users")
  .postData(jsonData)
  .header("Content-Type", "application/json")
  .header("Accept", "application/json")
  .asString

if (postResponse.code == 201) {
  println("User created successfully: " + postResponse.body)
} else {
  println("Error: " + postResponse.code + " - " + postResponse.body)
}

// POST with form data
val formResponse = Http("https://api.example.com/login")
  .postForm(Seq(
    "username" -> "testuser",
    "password" -> "secret123"
  ))
  .asString

// GET with query parameters
val searchResponse = Http("https://api.example.com/search")
  .param("q", "scala")
  .param("type", "repository")
  .param("sort", "stars")
  .asString

// Detailed response processing
val detailedResponse = Http("https://api.example.com/data").asString
detailedResponse match {
  case HttpResponse(body, 200, headers) =>
    println("Success: " + body)
  case HttpResponse(body, 404, _) =>
    println("Not found: " + body)
  case HttpResponse(body, code, _) =>
    println(s"Error $code: $body")
}

Advanced Configuration and Customization

import scalaj.http._
import scala.concurrent.duration._

// Timeout configuration
val timeoutResponse = Http("https://api.example.com/slow-endpoint")
  .timeout(connTimeoutMs = 5000, readTimeoutMs = 10000)
  .asString

// Custom headers
val customHeaderResponse = Http("https://api.example.com/secure")
  .header("Authorization", "Bearer your-jwt-token")
  .header("X-API-Version", "v2")
  .header("User-Agent", "MyScalaApp/1.0")
  .asString

// SSL configuration (for development)
val unsafeSslResponse = Http("https://localhost:8443/api/data")
  .option(HttpOptions.allowUnsafeSSL)
  .asString

// Proxy configuration
val proxyResponse = Http("https://api.example.com/data")
  .proxy("proxy.example.com", 8080)
  .asString

// Basic authentication
val basicAuthResponse = Http("https://api.example.com/protected")
  .auth("username", "password")
  .asString

// Complex request with multiple options
val complexRequest = Http("https://api.example.com/complex")
  .timeout(connTimeoutMs = 3000, readTimeoutMs = 15000)
  .header("Authorization", "Bearer token123")
  .option(HttpOptions.connTimeout(3000))
  .option(HttpOptions.readTimeout(15000))
  .option(HttpOptions.followRedirects(true))
  .asString

// Custom parser for response processing
case class User(id: Int, name: String, email: String)

val parsedResponse: HttpResponse[User] = Http("https://api.example.com/user/1")
  .execute(parser = { inputStream =>
    // Use custom JSON parser
    val jsonString = scala.io.Source.fromInputStream(inputStream).mkString
    // JSON parsing logic (using play-json, circe, etc.)
    parseUser(jsonString)
  })

def parseUser(json: String): User = {
  // JSON parsing implementation
  User(1, "Test User", "[email protected]")
}

OAuth 1.0 Authentication

import scalaj.http._

// OAuth 1.0 authentication setup
val consumer = Token("consumer-key", "consumer-secret")
val accessToken = Token("access-token", "access-token-secret")

// OAuth authenticated request
val oauthResponse = Http("https://api.twitter.com/1.1/statuses/user_timeline.json")
  .param("screen_name", "scala_lang")
  .oauth(consumer, Some(accessToken))
  .asString

if (oauthResponse.code == 200) {
  println("Twitter API success: " + oauthResponse.body)
} else {
  println("Twitter API error: " + oauthResponse.code)
}

// OAuth request token acquisition
val requestTokenResponse = Http("https://api.twitter.com/oauth/request_token")
  .postForm(Seq("oauth_callback" -> "oob"))
  .oauth(consumer)
  .asToken

requestTokenResponse match {
  case Right(token) =>
    println("Request token acquired: " + token.key)
  case Left(errorResponse) =>
    println("Request token acquisition failed: " + errorResponse.body)
}

File Upload

import scalaj.http._
import java.io.File

// File upload
val file = new File("/path/to/document.pdf")
val uploadResponse = Http("https://api.example.com/upload")
  .postMulti(MultiPart("file", "document.pdf", "application/pdf", file))
  .asString

// Multiple files with form data
val multipartResponse = Http("https://api.example.com/upload/multiple")
  .postMulti(
    MultiPart("title", "Document Title"),
    MultiPart("description", "File description"),
    MultiPart("file1", "doc1.pdf", "application/pdf", new File("/path/to/doc1.pdf")),
    MultiPart("file2", "image.jpg", "image/jpeg", new File("/path/to/image.jpg"))
  )
  .header("Authorization", "Bearer your-token")
  .asString

// Binary data upload
val binaryData: Array[Byte] = loadBinaryData()
val binaryResponse = Http("https://api.example.com/binary")
  .postData(binaryData)
  .header("Content-Type", "application/octet-stream")
  .asString

def loadBinaryData(): Array[Byte] = {
  // Binary data loading
  Array.emptyByteArray
}

Error Handling

import scalaj.http._
import scala.util.{Try, Success, Failure}

// Basic error handling
def safeHttpRequest(url: String): Either[String, String] = {
  Try {
    val response = Http(url).asString
    if (response.code >= 200 && response.code < 300) {
      Right(response.body)
    } else {
      Left(s"HTTP Error ${response.code}: ${response.body}")
    }
  } match {
    case Success(result) => result
    case Failure(exception) => Left(s"Network Error: ${exception.getMessage}")
  }
}

// Usage example
safeHttpRequest("https://api.example.com/data") match {
  case Right(data) => println("Success: " + data)
  case Left(error) => println("Error: " + error)
}

// Request with retry functionality
def httpWithRetry(url: String, maxRetries: Int = 3): HttpResponse[String] = {
  def attempt(retriesLeft: Int): HttpResponse[String] = {
    val response = Http(url).asString
    if (response.code >= 500 && retriesLeft > 0) {
      Thread.sleep(1000)  // Wait 1 second
      attempt(retriesLeft - 1)
    } else {
      response
    }
  }
  attempt(maxRetries)
}

// Exception-throwing error handling
val response = Http("https://api.example.com/data").asString
if (response.is2xx) {
  println("Success: " + response.body)
} else if (response.is4xx) {
  throw new RuntimeException(s"Client error: ${response.code}")
} else if (response.is5xx) {
  throw new RuntimeException(s"Server error: ${response.code}")
}

// Custom error handling
case class ApiError(code: Int, message: String, details: String)

def handleApiResponse(response: HttpResponse[String]): Either[ApiError, String] = {
  if (response.is2xx) {
    Right(response.body)
  } else {
    val errorMessage = response.code match {
      case 400 => "Bad request"
      case 401 => "Authentication required"
      case 403 => "Access denied"
      case 404 => "Resource not found"
      case 429 => "Rate limit reached"
      case 500 => "Internal server error"
      case _ => "Unexpected error"
    }
    Left(ApiError(response.code, errorMessage, response.body))
  }
}

Migration Guide (Example: scalaj-http to sttp)

// scalaj-http (deprecated)
import scalaj.http._
val response = Http("https://api.example.com/users").param("page", "1").asString

// sttp (recommended alternative)
import sttp.client3._
val response = basicRequest
  .get(uri"https://api.example.com/users?page=1")
  .send(backend)

Note: For new projects, we strongly recommend using actively developed alternatives like sttp, http4s, or Java HttpClient.