{"id":14989980,"url":"https://github.com/guzba/curly","last_synced_at":"2025-08-21T15:33:13.835Z","repository":{"id":65830016,"uuid":"587940543","full_name":"guzba/curly","owner":"guzba","description":"An easy to use and efficient thread-ready HTTP client.","archived":false,"fork":false,"pushed_at":"2024-10-07T06:08:29.000Z","size":247,"stargazers_count":56,"open_issues_count":1,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-08T12:47:06.836Z","etag":null,"topics":["curl","http","http-client","https","libcurl","multithreading","nim"],"latest_commit_sha":null,"homepage":"","language":"Nim","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/guzba.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2023-01-12T00:05:14.000Z","updated_at":"2025-04-03T21:23:40.000Z","dependencies_parsed_at":"2024-01-18T08:39:17.786Z","dependency_job_id":"5116957e-c44f-4949-944e-7f6686142066","html_url":"https://github.com/guzba/curly","commit_stats":{"total_commits":101,"total_committers":1,"mean_commits":101.0,"dds":0.0,"last_synced_commit":"52e3cc1157a7be3aca7c3bae9225b87b6233f059"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":"treeform/nimtemplate","purl":"pkg:github/guzba/curly","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guzba%2Fcurly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guzba%2Fcurly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guzba%2Fcurly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guzba%2Fcurly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guzba","download_url":"https://codeload.github.com/guzba/curly/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guzba%2Fcurly/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271500361,"owners_count":24770375,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-21T02:00:08.990Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["curl","http","http-client","https","libcurl","multithreading","nim"],"created_at":"2024-09-24T14:19:16.333Z","updated_at":"2025-08-21T15:33:13.558Z","avatar_url":"https://github.com/guzba.png","language":"Nim","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Curly\n\n`nimble install curly`\n\n![Github Actions](https://github.com/guzba/curly/workflows/Github%20Actions/badge.svg)\n\n[API reference](https://guzba.github.io/curly/)\n\nCurly is an efficient thread-ready parallel HTTP client built on top of libcurl.\n\nWith Curly you can run one or multiple HTTP requests in parallel and you control how and when you want to block.\n\nSome highlights are:\n\n* Automatic TCP connection re-use (a big performance benefit for HTTPS connections).\n* Uses HTTP/2 multiplexing when possible (multiple requests in-flight on one TCP connection).\n* Any number of threads can start any number of requests and choose their blocking / nonblocking behavior.\n* Gzip'ed response bodies are transparently uncompressed using [Zippy](https://github.com/guzba/zippy).\n* Control how many requests are allowed in-flight at the same time.\n\nBy choosing what blocks and doesn't block, you can manage your program's control flow however makes sense for you.\n\n### Getting started\n```nim\nimport curly\n\nlet curl = newCurly() # Best to start with a single long-lived instance\n```\n\n### A simple request\n```nim\nlet response = curl.post(\"https://...\", headers, body) # blocks until complete\n```\n\n### Multiple requests in parallel\n```nim\nvar batch: RequestBatch\nbatch.post(\"https://...\", headers, body)\nbatch.get(\"https://...\")\n\nfor (response, error) in curl.makeRequests(batch): # blocks until all are complete\n  if error == \"\":\n    echo response.code\n  else:\n    # Something prevented a response from being received, maybe a connection\n    # interruption, DNS failure, timeout etc. Error here contains more info.\n    echo error\n```\n\n### A single non-blocking request\n```nim\ncurl.startRequest(\"GET\", \"https://...\") # doesn't block\n\n# do whatever\n```\n\n### Multiple non-blocking requests\n```nim\nvar batch: RequestBatch\nbatch.get(url1)\nbatch.get(url2)\nbatch.get(url3)\nbatch.get(url4)\n\ncurl.startRequests(batch) # doesn't block\n\n# do whatever\n```\n\n### Handle responses to non-blocking requests by waiting for them\n```nim\nlet (response, error) = curl.waitForResponse() # blocks until a request is complete\nif error == \"\":\n  echo response.code\nelse:\n  echo error\n```\n\n### Handle responses to non-blocking requests by polling for them\n```nim\nlet answer = curl.pollForResponse() # checks if a request has completed\nif answer.isSome:\n  if answer.get.error == \"\":\n    echo answer.get.response.request.url\n    echo answer.get.response.code\n  else:\n    echo answer.get.error\n```\n\nCheck out the [examples/](https://github.com/guzba/curly/tree/master/examples) folder for examples using Curly.\n\n## Configuration\n\nWhen you create a Curly instance, you can optionally specify `maxInFlight`. This value lets you control the maximum HTTP requests that will be actively running at any time. The default `maxInFlight` value is 16.\n\nControlling `maxInFlight` is useful because it means you can queue up 100,000 requests and know that only say 100 of them will be in-flight at a time.\n\n## Queue management\n\nSince `startRequests` can add any number of HTTP requests to a queue, and since HTTP requests can block for a long time, it is really easy to find yourself with an ever-growing queue and run out of memory. This is no good.\n\nYou can ask a Curly instance how long its queue is (`queueLen`) and if you think that is too long, you can call `clearQueue`. Clearing the queue will unblock all threads waiting for responses and each queued request will have an error stating it was canceled.\n\n## A key difference from Nim's std/httpclient\n\nWhen using Nim's std/httpclient, it is expected that you use a new HttpClient or AsyncHttpClient for each request. This is both not needed and a bad idea with Curly.\n\nThis is because Curly reuses connections instead of setting them up and tearing them down for each request. A Curly instance should be long-lived, probably for the entire process lifespan.\n\nIt is a great starting point to simply have `let curl* = newCurly()` at the top of your program and use it everywhere for any number of requests from any number of threads.\n\n## Production tested\n\nI am using Curly in a production [Mummy](https://github.com/guzba/mummy) web server to make 20k+ HTTPS requests per minute on a tiny VM for a while now without any trouble.\n\nBoth the blocking and non-blocking Curly APIs are used and confirmed working in a very multi-threaded production environment.\n\n## Platform support\n\nCurly should work out-of-the-box on Linux and Mac.\n\nOn Windows you'll need to grab the latest libcurl DLL from https://curl.se/windows/, rename it to libcurl.dll, and put it in the same directory as your executable.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguzba%2Fcurly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguzba%2Fcurly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguzba%2Fcurly/lists"}