# Handle Large Data Request - [Handle Large Data Request](#handle-large-data-request) - [Track Progress](#track-progress) - [Cancel Downloads with resumable data](#cancel-downloads-with-resumable-data) - [Resume Downloads](#resume-downloads) When sending relatively small amounts of data to a server using JSON or URL encoded parameters data you don't need to setup anything. ## Track Progress If you need to send much larger amounts of data from Data in memory, a file URL, or an InputStream, we suggest setting the appropriate `.largeData` options for `transferMode` property. It allows you to track the progress of the upload: ```swift let req = HTTPRequest { $0.url = URL(string: "http://ipv4.download.thinkbroadband.com/5MB.zip")! $0.transferMode = .largeData $0.method = .get } // You can monitor the progress via Combine APIs req.$progress.sink { progress in print("Downloading percentage: \(progress?.percentage ?? 0)%") }.store(in: &observerBag) let response = try await req.fetch(client) ``` When using `.largeData` transfer mode the data is automatically downloaded on a temporary file located in `.dataFileURL` property. > **NOTE**: If you call `.data` instead of `.dataFileURL` the data contained into the file will be automatically pushed into the RAM. Consider it especially for large file transfer. `progress` property is of type `HTTPProgress` which is a struct with the following properties: - `event`: kind of progress event (`upload` or `download` which is triggered multiple times during the transfer operation. `failed` or `resumed` is sent once only when download has failed, as last track report, or `resumed` as first track report followed by `upload/download` events). - `progress`: the instance of `Progress` object you can use to update the UI - `currentLength` and `expectedLength` with the current status of the transfer and the total expected size (not all server will return these data, so you may found both values set to 0). - `percentage`: if tracking is available from server side this value represent the percentage of the transfer. - `partialData`: once transfer fails this contains the partial downloaded data. ## Cancel Downloads with resumable data Bad things happend. If your download fails due to network failure or because your user wanna cancel it, you may want to store partially downloaded data in order to attempt to resume the download itself. **If you want to cancel a download** ensure to call `cancel(byProducingResumeData:)` with a valid callback. The callback will contains a copy of the partial data you can store in a temporary directory to resume the download. For example: ```swift // Somewhere your code you may want to cancel the download // and leave the option to resume it. req.cancel(byProducingResumeData: { partialData in let partialDataURL = URL(file: "/sandbox/location") try partialData.write(to: partialDataURL) // resumable data }) ``` **If your downlod fails due to network error** the last progress message contains the path to the resumable data: ```swift req.$progress.sink { progress in if progress?.event == .failed, let partialData = progress?.partialData { // save it somewhere or assign directly to a new request's `.partialData` saveDataInTempLocation(partialData) } }.store(in: &observerBag) ``` moreover the `HTTPResponse` object returned contains `dataFileURL` with the temporary data written to file. > **NOTE:** Its your own responsibility to remove these partial data file from disk. ## Resume Downloads In order to resume downloads with a partial data you set the `partialData` property of the `HTTPRequest` (and set `transferMode` to `.largeData`): ```swift let req = HTTPRequest(...) req.partialData = ... // your saved partial data req.$progress.sink { progress in // You will receive a first progress.event == .resumed message if // resume is occurred successfully. // If you don't receive it resume has failed and the download started over. // The next progress messages are download/upload or fail. }.store(in: &observerBag) let response = try await req.fetch(client) ```