{"id":25238000,"url":"https://github.com/vspaz/scala-http","last_synced_at":"2026-02-21T06:05:22.675Z","repository":{"id":65265772,"uuid":"580765263","full_name":"vspaz/scala-http","owner":"vspaz","description":"a scala http client that supports request retries on specific errors \u0026 exceptions, json serialization and deserialization, authentication etc. in a simple way.","archived":false,"fork":false,"pushed_at":"2025-03-25T20:56:29.000Z","size":138,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-13T18:09:00.380Z","etag":null,"topics":["error-handling","exceptions","http","http-client","retries","scala"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vspaz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-12-21T11:47:49.000Z","updated_at":"2025-03-25T20:55:49.000Z","dependencies_parsed_at":"2023-02-10T11:15:48.700Z","dependency_job_id":"58a2dc6f-2f29-4e8b-868f-35c47b376020","html_url":"https://github.com/vspaz/scala-http","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/vspaz/scala-http","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vspaz%2Fscala-http","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vspaz%2Fscala-http/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vspaz%2Fscala-http/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vspaz%2Fscala-http/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vspaz","download_url":"https://codeload.github.com/vspaz/scala-http/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vspaz%2Fscala-http/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29674940,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T05:54:28.202Z","status":"ssl_error","status_checked_at":"2026-02-21T05:53:42.585Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["error-handling","exceptions","http","http-client","retries","scala"],"created_at":"2025-02-11T16:03:04.909Z","updated_at":"2026-02-21T06:05:22.658Z","avatar_url":"https://github.com/vspaz.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# scala-http\n\nan HTTP client that's simple to configure \u0026 use.\nit provides a simple configuration for:\n- request retries on specific HTTP errors \u0026 exceptions\n- timeouts (connection, read, idle etc.)\n- basic \u0026 token auth\n- json serialization \u0026 deserialization out of the box\n- extra helpers\n- logging\netc.\n\n### How-to:\n\n#### Use the client w/o any configuration\n\n####  Do simple GET request\n\n```scala\nimport org.junit.jupiter.api.Assertions.{assertEquals, assertTrue}\nimport org.vspaz.http.Client\n\nval resp = new Client().doGet(endpoint = \"https://httpbin.org/get\")\nassertTrue(resp.isOk())\nassertTrue(resp.isSuccess())\nassertEquals(200, resp.statusCode)\n```\n\n#### Deserialize JSON payload\n\n```scala\nimport org.junit.jupiter.api.Assertions.{assertEquals, assertTrue}\nimport org.vspaz.http.Client\n\ncase class Response(\n                     args: Option[Map[String, String]],\n                     headers: Option[Map[String, String]],\n                     origin: Option[String],\n                     url: Option[String]) {}\n```\n\n```scala\nval resp = new Client().doGet(endpoint = \"https://httpbin.org/get\")\nassertTrue(resp.isOk())\n\nval decodedBody = resp.fromJson(classOf[Response])\nassertEquals(\"https://httpbin.org/get\", decodedBody.url.get)\n```\n\nor if you need more control, you can get response as bytes or string, \nand deserialize it with any Scala/Java frameworks e.g.\n\n```scala\nimport com.fasterxml.jackson.databind.json.JsonMapper\nimport com.fasterxml.jackson.module.scala.DefaultScalaModule\n\nval resp = new Client().doGet(endpoint = \"https://httpbin.org/get\")\nassertTrue(resp.isOk())\n\nval mapper: JsonMapper = JsonMapper.builder().addModule(DefaultScalaModule).build()\nval decodedBody = mapper.readValue(response.toString(), classOf[Response])\n```\n\n#### Add query params to request\n\n```scala\nval resp = new Client().doGet(endpoint = \"https://httpbin.org/get\", params = Map(\"foo\" -\u003e \"bar\"))\nassertTrue(resp.isOk())\n    \nval decodedBody = resp.fromJson(classOf[Response])\nassertEquals(\"https://httpbin.org/get?foo=bar\", decodedBody.url.get)\nassertEquals(\"bar\", decodedBody.args.get(\"foo\"))\n```\n\n#### Add headers to request\n\n```scala\nval resp = new Client().doGet(endpoint = \"https://httpbin.org/get\", headers = Map(\"Header-Type\" -\u003e \"header-value\"))\nassertTrue(resp.isOk())\n\nval decodedBody = resp.fromJson(classOf[Response])\nassertEquals(\"header-value\", decodedBody.headers.get(\"Header-Type\"))\n```\n\n#### Get response headers\n```scala\nval resp = new Client().doGet(endpoint = \"https://httpbin.org/get\")\nassertTrue(resp.isOk())\n\nprintln(resp.headers)\nassertEquals(\"application/json\", resp.headers(\"content-type\"))\n```\n\n### Configuring HTTP client\n\n#### Retrying request on HTTP errors \u0026 exceptions\n\n* `retryCount[Int]`:  number of attempts to retry the request before it fails\n* `retryDelay [Int]`: incremental retry delay between requests (sec)\n* `retryOnStatusCodes Set[Int]`: a set of http status codes to retry on\n* `retryOnExceptions Set[Int]`: a st of exceptions to retry on\n```scala\nimport org.vspaz.http.Client\n\nval client = new Client(\n      host = \"https://httpbin.org\",\n      userAgent = \"client-name-and-version\",\n      retryCount = 3,\n      retryDelay = 1,\n      retryOnStatusCodes = Set(400, 500, 503),\n      retryOnExceptions = Set(\n        \"java.lang.RuntimeException\",\n        \"java.lang.Throwable\"\n      )\n    )\n\nval resp = client.doGet(endpoint = \"/get\")\nassertTrue(resp.isOk())\n\n```\n\n#### JSON serialization\n\n1. implicit json serialization\n\n```scala\nval client = new Client(\n  host = \"https://httpbin.org\",\n  userAgent = \"client-name-and-version\"\n)\n\nval resp = client.doPost(\n  endpoint = \"/post\",\n  headers = Map(\"Content-Type\" -\u003e \"application/json\"),\n  payload = Map(\"key\" -\u003e \"  value\")\n)\n```\n\n2. explicit json serialization\n\n```scala\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport com.fasterxml.jackson.module.scala.DefaultScalaModule\n\nval client = new Client(\n  host = \"https://httpbin.org\",\n  userAgent = \"client-name-and-version\"\n)\n\nval mapper: ObjectMapper = new ObjectMapper()\nmapper.registerModule(DefaultScalaModule)\n\nval resp = client.doPost(\n  endpoint = \"/post\",\n  headers = Map(\"Content-Type\" -\u003e \"application/json\"),\n  payload = mapper.writer.writeValueAsString(Map(\"key\" -\u003e \"value\"))\n)\n```\n\n#### JSON deserialization\n\n```scala\npackage org.vspaz\n\n\nimport org.junit.jupiter.api.Assertions.{assertEquals, assertTrue}\nimport org.vspaz.http.Client\n\ncase class Response(\n                     args: Option[Map[String, String]],\n                     headers: Option[Map[String, String]],\n                     origin: Option[String],\n                     url: Option[String]) {}\n\nval client = new Client(\n  host = \"https://httpbin.org\",\n  userAgent = \"client-name-and-version\"\n)\n\nval resp = client.doGet(endpoint = \"/get\")\nassertTrue(resp.isOk())\nval decodedBody = resp.fromJson(classOf[Response])\n```\n\n### Authentication\n\n1. Basic auth\n\n* `basicAuthUser`: username\n* `basicUserPassword`: user password\n\n```scala\n val client = new Client(\n  host = \"https://httpbin.org\",\n  userAgent = \"client-name-and-version\",\n  basicAuthUser = \"user\",\n  basicUserPassword = \"pass\"\n)\n\nval resp = client.doGet(endpoint = \"/get\")\nassertTrue(resp.isOk())\n\n```\n\n2. Bearer token authentication\n\n* `token`: bearer token.\n\n```scala\n\nval client = new Client(\n  host = \"https://httpbin.org\",\n  userAgent =\"client-name-and-version\",\n  token = \"iEtTTpwwPKcLNKSykKmN\"\n)\n\nval resp = client.doGet(endpoint = \"/get\")\nassertTrue(resp.isOk())\n\n// or\n\nval resp = client.doGet(endpoint = \"/get\", headers = Map(\"Authorization\" -\u003e s\"Bearer iEtTTpwwPKcLNKSykKmN\"))\nassertTrue(resp.isOk())\n\n```\n\n### Timeouts\n\n* `connectionTimeout`: connection timeout (sec)\n* `readTimeout`: read timeout (sec)\n\n```scala\nval client = new Client(\n  host = \"https://httpbin.org\",\n  userAgent = \"client-name-and-version\",\n  connectionTimeout = 5,\n  readTimeout = 10\n)\n\nval resp = client.doGet(endpoint = \"/get\")\nassertTrue(resp.isOk())\n\n```\n\n### Full Client configuration\n\nall parameters are optional\n\n* `host`[String]: optional, default is an empty string\n* `userAgent`[String]: optional, no default\n* `basicAuthUser`[String]: optional, no default\n* `basicUserPassword`[String]:  optional, no default\n* `token`[String]:  optional, no default\n* `retryCount`[Int]: default = 0, number of retries before request fails\n* `retryOnStatusCodes`[Set[Int]]: default is an empty set\n* `retryOnExceptions`[Set[String]]: default is an empty set\n* `retryDelay`[Int]: default = 0\n* `readTimeout`[Int]: default = 10 sec\n* `connectionTimeout`[Int]: default = 10 sec\n* `logger`[Logger]:\n\n```scala\nimport org.vspaz.http.Client\n\nval client = new Client(\n  host = \"https://httpbin.org\",\n  userAgent = \"client-name-and-version\",\n  basicAuthUser = \"username\",\n  basicUserPassword = \"pass\",\n  token = \"\",\n  retryCount = 3,\n  retryDelay = 1,\n  retryOnStatusCodes = Set(400, 500, 503),\n  retryOnExceptions = Set(\n    \"java.lang.RuntimeException\",\n    \"java.lang.Throwable\"\n  ),\n  connectionTimeout = 5,\n  readTimeout = 10\n)\n```\n\n### Response object\n```scala\nimport org.junit.jupiter.api.Assertions.{assertEquals, assertTrue}\nimport org.vspaz.http.Client\n\nval resp = new Client().doGet(endpoint = \"https://httpbin.org/get\")\nassertTrue(resp.isOk())\nassertTrue(resp.isSuccess())\nassertEquals(200, resp.statusCode)\nprintln(resp.asString())\nprintln(resp.asBytes())\nprintln(resp.headers)\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvspaz%2Fscala-http","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvspaz%2Fscala-http","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvspaz%2Fscala-http/lists"}