{"id":24183948,"url":"https://github.com/cioccarellia/kurl","last_synced_at":"2026-03-08T11:31:27.453Z","repository":{"id":144472339,"uuid":"232827501","full_name":"cioccarellia/Kurl","owner":"cioccarellia","description":"Structures and shapes backend interaction with pure idiomatic Kotlin","archived":false,"fork":false,"pushed_at":"2021-01-01T21:41:02.000Z","size":255,"stargazers_count":12,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-03T22:36:33.566Z","etag":null,"topics":["api","backend","builder","curl","dsl","kotlin","kotlin-android","kotlin-library","url"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cioccarellia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","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},"funding":{"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["https://www.paypal.me/andreacioccarelli"]}},"created_at":"2020-01-09T14:26:52.000Z","updated_at":"2024-01-28T16:02:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"81c5657e-10a3-40f6-bd0d-3730ff497a55","html_url":"https://github.com/cioccarellia/Kurl","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/cioccarellia/Kurl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cioccarellia%2FKurl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cioccarellia%2FKurl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cioccarellia%2FKurl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cioccarellia%2FKurl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cioccarellia","download_url":"https://codeload.github.com/cioccarellia/Kurl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cioccarellia%2FKurl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276204814,"owners_count":25602738,"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-09-21T02:00:07.055Z","response_time":72,"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":["api","backend","builder","curl","dsl","kotlin","kotlin-android","kotlin-library","url"],"created_at":"2025-01-13T09:32:02.521Z","updated_at":"2025-09-21T06:32:21.889Z","avatar_url":"https://github.com/cioccarellia.png","language":"Kotlin","funding_links":["https://www.paypal.me/andreacioccarelli"],"categories":[],"sub_categories":[],"readme":"# Kurl\n[![Download](https://api.bintray.com/packages/cioccarellia/kurl/kurl/images/download.svg)](https://bintray.com/cioccarellia/kurl/kurl/_latestVersion)\n[![CircleCI](https://circleci.com/gh/cioccarellia/Kurl.svg?style=svg)](https://circleci.com/gh/cioccarellia/Kurl/tree/master)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/2d207f5ac27b4aed8276803b18c29115)](https://www.codacy.com/manual/cioccarellia/Kurl?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=AndreaCioccarelli/Kurl\u0026amp;utm_campaign=Badge_Grade)\n[![codecov](https://codecov.io/gh/cioccarellia/Kurl/branch/master/graph/badge.svg)](https://codecov.io/gh/cioccarellia/Kurl)\n[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Kurl-green.svg?style=flat)](https://android-arsenal.com/details/1/8031)\n[![Kotlin](https://img.shields.io/badge/Kotlin-1.3.70-orange.svg?style=flat)](https://kotlinlang.org)\n[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0.html)\n\nKurl is a library that implements, structures, modularizes and provides testability for backend APIs implementations.\nIt is designed to turn basic strings (and URLs) operations into consistent and idiomatic Kotlin code.\n\nKurl is designed from the ground up to perform all the heavy and error-prone work, leaving you with higher level abstraction and logic.\nKurl stands for _Kotlin Url Repolishing Library_. The name is inspired by [cUrl](https://curl.haxx.se).\n\n## Setup\nKurl is available on any JVM-targeted platform (Android, Desktop, Server).\n#### Add dependency\n\n\u003cdetails open\u003e\u003csummary\u003eGradle\u003c/summary\u003e\n\n```gradle\ndependencies {\n    implementation 'com.cioccarellia:kurl:1.0.4'\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eMaven\u003c/summary\u003e\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.cioccarellia\u003c/groupId\u003e\n    \u003cartifactId\u003ekurl\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.4\u003c/version\u003e\n    \u003ctype\u003epom\u003c/type\u003e\n\u003c/dependency\u003e\n```\n\u003c/details\u003e\n\n\n## Introduction\nIf you have some backend interaction background, you can feel ok with skipping this part, it's just a technical brush up to make sure we're all on the same page.\n\nAn API url is _where_ the server hosts the service you use.\nTo create software which is capable of accessing a minimally structured API you have to know the API url and the scheme used by the server.\n\nAn URL is composed by several parts. \nGenerally, we can group them into 3 categories:\n\n```\nhttps://api.github.com/users/AndreaCioccarelli/repos/Kurl\n```\n- Protocol: `https`\n- Domain: `api.github.com`\n- Web Path: `users/AndreaCioccarelli/repos/Kurl`\n\nIn the case above the root API url matches with the domain itself, but if we take:\n\n```\nhttps://swapi.co/api/people/3\n```\n\nThe general url composition will see `swapi.co` as the domain and `api/people/3` as it's web path, and this is correct, but to be precise, the root API url is `swapi.co/api` (Because it is where all the requests are dispatched to), and the endpoint we want to access is `people/1` (because it's the path we append to the API root to access our desired endpoint).\n\n## Kurl Docs\nYou use a `kurl` launcher function to start composing your request.\nKurl provides a DSL with a set of methods to shape it up.\n\nIt returns an object of `KurlRequest` type.\nThere are a bunch of functions and extensions you can invoke to start using Kurl:\n\n```kotlin\nval id = 3\n\nval request = kurl(\"https://swapi.co/api\") {\n    endpoint(\"people/$id\")\n}\n```\n\n```kotlin\nval r2d2Id = 3\n\nval api = Api(\n    domain = \"swapi.co\",\n    path = \"api\"\n)\n\nval people = Endpoint(\"people\")\n\n\nval request1 = kurl(api, people) {\n    endpoint(\"$r2d2Id\")\n}\n\nval request2 = api.kurl(people) {\n    endpoint(\"$r2d2Id\")\n}\n```\n\nInside the lambda block you can invoke functions which will be used to compose the final request.\n- `endpoint()`: Appends the passed string to the request url.\n- `parameters()`: Sets the passed key-value pairs as the URL query.\n- `headers()`: Sets the header value for the header key for every entry you passed.\n- `fragment()`: Sets the fragment tag at the end of the url.\n\nOnce the lambda has been executed a request object is returned.\nIt contains all the finalized information needed to extract the required url, plus, additional useful methods for testing and checking the url.\n\nThe core library can also be used alongside a **kurl-ktx** dependency for supported HTTP clients, in order to support a bunch of specific features and to reduce the code you need to write.\n\n### Api\nAn `Api` object describes a certain API root path.\nIt can be created either namely or directly.\n\n_Namely_ creating an API instance means passing all the needed arguments inside the class primary constructor.\n```kotlin\nApi(\n    domain = \"swapi.co\",\n    path = \"api\"\n)\n```\nThis should be the default choice for your implementation, as it provides better readability.\nKurl is smart enough to infer and stick together the url you want to create even if you don't pass in every parameter, and to perform basic input error checking and correction.\nThe default protocol is HTTPS. All other fields are optional.\nThe only mandatory parameter is `domain`.\n\n_Directly_ creating an API instance means that you pass in the url using the `direct()` function and that's it. \nNo smart insertion or completion is performed, the precise  exact string you type in is decomposed and used as the API root url.\n```kotlin\nApi.direct(\"https://swapi.com/api\")\n```\n\n### Endpoint\n`Endpoint` is just a class representing a piece of an URL.\nDepending on the context, Kurl internally trims and concatenates different endpoints together, basing on how you input them.\n\nThe difference between an `Api` and an `Endpoint` is that the first one is unique, and the second one can be composed (You can stick together different endpoints to reach your target configuration).\n\n### Containers\nYou can make use of a `KurlApiContainer` to create a structured and specific API object.\nThis will group your app's API components in one place, instead of having them all scattered around your codebase.\n\n```kotlin\nclass StarWarsApiContainer : KurlApiContainer() {\n\n    val api = Api(\n        domain = \"swapi.co\",\n        path = \"/api/\"\n        // \"api\", \"/api\" and \"api/\" are ok too, Kurl will remove \n        // and add any needed slash since we're doing things namely.\n    )\n\n    val lukeUrl: KurlRequest\n        get() = kurl(\n            Endpoint(\"people/1\")\n        )\n\n    fun getPersonById(id: Into): String = kurl {\n        endpoint(\"people/$id\")\n    }.url()\n\n    fun getRandomStarship(): KurlRequest = kurl {\n        val rid = Random().nextInt(1, 9)\n        endpoint(\"starships/$rid\")\n    }\n}\n```\nNice touches with a `KurlApiContainer` are:\n- You don't need to pass in an Api object every time you invoke `kurl`, it is automatically inferred by the context.\n- You can make use of inner classes to split in logical pieces your container\n\n# Kurl KTX\nThe Kurl core package is designed to build kurl requests.\nIf your client is supported by Kurl, you may consider including its specific KTX module, in order to simplify even more the integration process.\n\nEach extension module contains the same exact features, adapted to the specific client syntax.\n- Kurl injection on request builders.\n- Conversion from Kurl requests to client specific requests.\n- Library agnostic type conversion \u0026 support.\n\n## Ktor KTX\n[![Download](https://api.bintray.com/packages/cioccarellia/kurl/kurl-ktx-ktor/images/download.svg)](https://bintray.com/cioccarellia/kurl/kurl-ktx-ktor/_latestVersion)\n[![Ktor](https://img.shields.io/badge/Ktor-1.5.0-purple.svg?style=flat)](https://ktor.io)\n\n\n\u003cdetails open\u003e\u003csummary\u003eGradle\u003c/summary\u003e\n\n```gradle\ndependencies {\n    implementation 'com.cioccarellia:kurl-ktx-ktor:1.0.4'\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eMaven\u003c/summary\u003e\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.cioccarellia\u003c/groupId\u003e\n  \u003cartifactId\u003ekurl-ktx-ktor\u003c/artifactId\u003e\n  \u003cversion\u003e1.0.4\u003c/version\u003e\n  \u003ctype\u003epom\u003c/type\u003e\n\u003c/dependency\u003e\n```\n\u003c/details\u003e\n\n\n## OkHttp KTX\n[![Download](https://api.bintray.com/packages/cioccarellia/kurl/kurl-ktx-okhttp/images/download.svg)](https://bintray.com/cioccarellia/kurl/kurl-ktx-okhttp/_latestVersion)\n[![OkHttp](https://img.shields.io/badge/OkHttp-4.9.0-purple.svg?style=flat)](https://square.github.com/okhttp/)\n\n\u003cdetails open\u003e\u003csummary\u003eGradle\u003c/summary\u003e\n\n```gradle\ndependencies {\n    implementation 'com.cioccarellia:kurl-ktx-okhttp:1.0.4'\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eMaven\u003c/summary\u003e\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.cioccarellia\u003c/groupId\u003e\n  \u003cartifactId\u003ekurl-ktx-okhttp\u003c/artifactId\u003e\n  \u003cversion\u003e1.0.4\u003c/version\u003e\n  \u003ctype\u003epom\u003c/type\u003e\n\u003c/dependency\u003e\n```\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcioccarellia%2Fkurl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcioccarellia%2Fkurl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcioccarellia%2Fkurl/lists"}