{"id":19685909,"url":"https://github.com/rxswiftcommunity/rxhttpclient","last_synced_at":"2025-06-16T03:05:03.948Z","repository":{"id":138430683,"uuid":"62549077","full_name":"RxSwiftCommunity/RxHttpClient","owner":"RxSwiftCommunity","description":"Simple Http client (Use RxSwift for stream data)","archived":false,"fork":false,"pushed_at":"2021-02-17T16:21:21.000Z","size":40148,"stargazers_count":38,"open_issues_count":2,"forks_count":8,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-05T13:51:24.286Z","etag":null,"topics":["nsurlsession","rxswift","streaming-data","swift"],"latest_commit_sha":null,"homepage":null,"language":"Swift","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/RxSwiftCommunity.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":"2016-07-04T09:21:35.000Z","updated_at":"2024-03-04T04:10:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"adf6c3f2-5100-4a23-a181-396fd6c0b798","html_url":"https://github.com/RxSwiftCommunity/RxHttpClient","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RxSwiftCommunity%2FRxHttpClient","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RxSwiftCommunity%2FRxHttpClient/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RxSwiftCommunity%2FRxHttpClient/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RxSwiftCommunity%2FRxHttpClient/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RxSwiftCommunity","download_url":"https://codeload.github.com/RxSwiftCommunity/RxHttpClient/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251450656,"owners_count":21591407,"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","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":["nsurlsession","rxswift","streaming-data","swift"],"created_at":"2024-11-11T18:24:40.023Z","updated_at":"2025-04-29T06:31:09.749Z","avatar_url":"https://github.com/RxSwiftCommunity.png","language":"Swift","readme":"RxHttpClient\n----\n[![Build Status](https://travis-ci.org/RxSwiftCommunity/RxHttpClient.svg?branch=master)](https://travis-ci.org/RxSwiftCommunity/RxHttpClient)\n[![codecov](https://codecov.io/gh/RxSwiftCommunity/RxHttpClient/branch/master/graph/badge.svg)](https://codecov.io/gh/RxSwiftCommunity/RxHttpClient)\n![Platform iOS](https://img.shields.io/badge/platform-iOS-lightgray.svg)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![codebeat badge](https://codebeat.co/badges/be008a71-5755-48fa-a861-8ce0d880ee14)](https://codebeat.co/projects/github-com-rxswiftcommunity-rxhttpclient-master)\n\nRxHttpClient is a \"reactive wrapper\" around NSURLSession. Under the hood it implements session delegates (like NSURLSessionDelegate or NSURLSessionTaskDelegate) and translates session events into Observables using [RxSwift](https://github.com/ReactiveX/RxSwift). Main purpose of this framework is to make \"streaming\" data as simple as possible and provide convenient features for caching data.\n\n## Requirements\n- Xcode 10.0\n- Swift 4.2\n\n## Installation\nNow only [Carthage](https://github.com/Carthage/Carthage) supported:\n```\ngithub \"ReactiveX/RxSwift\" ~\u003e 4.0\ngithub \"RxSwiftCommunity/RxHttpClient\"\n```\nRxHttpClient uses RxSwift so it should be included into cartfile.\n\n```\ncarthage update RxSwift\ncarthage update RxHttpClient\n```\nCommands above are necessary if Carthage trying to build RxHttpClient before RxSwift.\n\n## Usage\n#### StreamData\nFor create request and streaming data:\n```swift\nlet client = HttpClient()\nlet bag = DisposeBag()\nlet url = URL(string: \"url_to_resource\")!\nclient.request(url: url).subscribe (onNext: { event in\n  switch event {\n  case StreamTaskEvents.receiveResponse(let response): break /* Occurs after receiving response from remote server */\n  case StreamTaskEvents.receiveData(let data): break /* Occurs after receiving chunk of data from server (generally occurred many times) */\n  case StreamTaskEvents.error(let error): break /* Occurs in case of client-side error */\n  case StreamTaskEvents.success: break /* Occurs after successful completion of request */\n  default: break\n  }\n}).addDisposableTo(bag)\n```\n\nIf dealing with every chunk of data is not necessary it's possible to pass an instance of cache provider and in success event grab all data from that provider (for now there is only MemoryCacheProvider object):\n```swift\nlet client = HttpClient()\nlet bag = DisposeBag()\nlet url = URL(string: \"url_to_resource\")!\nclient.request(url: url, dataCacheProvider: MemoryCacheProvider()).subscribe(onNext: { event in\n  guard case StreamTaskEvents.success(let dataCacheProvider) = event else { return }\n\n  if let dataCacheProvider = dataCacheProvider {\n    // getting cached data from provider\n    let downloadedData = dataCacheProvider.getData()\n  }\n}).addDisposableTo(bag)\n```\n\n#### Convenience methods\nIt's also possible to simply invoke request and receive data using loadData method (in this case errors are forwarded with RxSwift error mechanism):\n```swift\nlet client = HttpClient()\nlet bag = DisposeBag()\nlet url = URL(string: \"url_to_resource\")!\n// by default HTTP GET request will be performed\nclient.requestData(url: url).subscribe(onNext: { data in /* do something with returned data */ }, onError: { error in\n  switch error {\n  case HttpClientError.clientSideError(let error): break /* Client-side error */\n  case let HttpClientError.invalidResponse(response, data): break /* Occurs when server did't return success HTTP code (not in 2xx) */\n  default: break\n  }\n}).addDisposableTo(bag)\n\n// use HTTP POST and send data\nlet sendJson = [\"Key1\":\"Value1\", \"Key2\":\"Value2\"]\nlet sendJsonData = try! JSONSerialization.data(withJSONObject: sendJson, options: [])\nclient.requestData(url: url, method: .post, body: sendJsonData).subscribe(onNext: { data in /* do something with returned data */ }).addDisposableTo(bag)\n\n// or simply pass JSON as parameter\nlet sendJson = [\"Key1\":\"Value1\", \"Key2\":\"Value2\"]\nclient.requestData(url: url, method: .put, jsonBody: sendJson, options: [], httpHeaders: [\"Header1\": \"HeaderVal1\"]).subscribe(onNext: { _ in expectation.fulfill() }).addDisposableTo(bag)\n```\n\nJSON deserialized object may be requested in same way:\n\n```swift\nlet client = HttpClient()\nlet bag = DisposeBag()\nlet url = URL(string: \"url_to_resource\")!\nclient.requestJson(url: url).subscribe(onNext: { json in /* do something with returned data */ }, onError: { error in\n  switch error {\n  case HttpClientError.clientSideError(let error): break /* Client-side error */\n  case let HttpClientError.invalidResponse(response, data): break /* Occurs when server did't return success HTTP code (not in 2xx) */\n  default: break\n  }\n}).addDisposableTo(bag)\n```\n\n#### Response caching\nHttpClient can cache latest response for GET request. To use caching, HttpClient should be initialized with instance of UrlRequestCacheProviderType:\n\n```swift\n// directory where cache data will be saved\nlet cacheDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent(\"Cache\")\n// instance of UrlRequestFileSystemCacheProvider that will store cached data in specified directory\nlet urlCacheProvider = UrlRequestFileSystemCacheProvider(cacheDirectory: cacheDirectory)\nlet client = HttpClient(urlRequestCacheProvider: urlCacheProvider)\n\n// Use specific cache mode for request\n// If data for URL already cached, this data will be returned immediately and after that request to the server will be invoked\nclient.requestJson(url: url, requestCacheMode: CacheMode(cacheResponse: true, returnCachedResponse: true, invokeRequest: true)).subscribe( /* */).addDisposableTo(bag)\n\n// If returnCachedResponse is false, cached data will not be returned even if exists\nclient.requestJson(url: url, requestCacheMode: CacheMode(cacheResponse: true, returnCachedResponse: false, invokeRequest: true)).subscribe( /* */).addDisposableTo(bag)\n\n// use predefined mode\n// \"offline mode\", use only cache and don't invoke request to server\nclient.requestJson(url: url, requestCacheMode: .cacheOnly).subscribe( /* */).addDisposableTo(bag)\n```  \n\n#### StreamDataTask\nStreamDataTask is a more \"low level\" object that wraps NSURLSessionDataTask. In most situations is't more convenient to use loadStreamData method (it actually simply forwards events from StreamDataTask), but if necessary StreamDataTask may be used in this way:\n```swift\nlet client = HttpClient()\nlet bag = DisposeBag()\nlet url = URL(string: \"url_to_resource\")!\n//let request = client.createUrlRequest(url, headers: [\"Header\": \"Value\"])\nlet request = URLRequest(url: url, headers: [\"Header\": \"Value\"])\nlet task = client.createStreamDataTask(request: request, cacheProvider: nil)\n// represents same events as loadStreamData method\ntask.taskProgress.subscribe(onNext: { event in\n  switch event {\n  case StreamTaskEvents.receiveResponse(let response): break /* Occurs after receiving response from remote server */\n  case StreamTaskEvents.receiveData(let data): break /* Occurs after receiving chunk of data from server (generally occurred many times) */\n  case StreamTaskEvents.error(let error): break /* Occurs in case of client-side error */\n  case StreamTaskEvents.success: break /* Occurs after successful completion of request */\n  default: break\n  }\n  }).addDisposableTo(bag)\n\n// resume task\ntask.resume()\n```\n\n#### MIME type conversion\nThis framework also contains useful methods to convert, for example, MIME type to file extension, or UTI type to MIME type:\n```swift\nlet extension = MimeTypeConverter.utiToFileExtension(\"public.mp3\") // returns \"mp3\"\nlet uti = MimeTypeConverter.mimeToUti(\"audio/mpeg\") // returns \"public.mp3\"\n\n// it also works with strings\nlet mime = \"public.mp3\".asUtiType.mimeType // returns \"audio/mpeg\"\n```\n\n## How it works\nHttpClient object holds it's own NSURLSession. It creates session by providing a session delegate object for handling session-related events. So StreamTaskEvents enum actually represents this session events, for example `case receiveResponse(URLResponse)` means that `URLSession(_:dataTask:didReceiveResponse:completionHandler:)` delegate method was invoked.\nBecause NSURLSession holds strong reference to delegate it should be invalidated, HttpClient do that in deinitializer by invoking finishTasksAndInvalidate() method, so session will allow running tasks to finish work.\n\n## License\n\nCopyright (c) 2017 RxSwiftCommunity https://github.com/RxSwiftCommunity\n\nDistributed under The MIT License:\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frxswiftcommunity%2Frxhttpclient","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frxswiftcommunity%2Frxhttpclient","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frxswiftcommunity%2Frxhttpclient/lists"}